Java – Criteria API – 单向 OneToMany

huangapple go评论95阅读模式
英文:

Java - Criteria API - Unidirectional OneToMany

问题

I have translated the provided content into Chinese as you requested:

  1. 我正试图通过Criteria API从流程表中获取人员的许可证号码。基本上是从`Process -> Person -> License`
  2. 然而,Person表与License表之间有一个单向的OneToMany关系。
  3. 所以我有以下的实体类:

@Entity
@Table(name = "Process")
public class Process {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;

  1. @OneToOne(fetch = FetchType.EAGER)
  2. @JoinColumn(name = "person_id")
  3. Person person;

}

@Entity
@Table(name = "Person")
public class Person {
@Id
@Column(name = "id", columnDefinition="INTEGER")
@GeneratedValue(strategy = GenerationType.IDENTITY)
Integer id;

  1. @OneToMany(fetch = FetchType.LAZY, mappedBy = "person")
  2. List<License> licenses;

}

@Entity
@Table(name = "License")
public class License {
@Id
@Column(name = "id", columnDefinition="INTEGER")
@GeneratedValue(strategy = GenerationType.IDENTITY)
Integer id;

  1. @JoinColumn(name = "person_id")
  2. @ManyToOne(fetch = FetchType.LAZY)
  3. Person person;
  4. String licenseNumber;

}

  1. 在一个原生查询中,我想要实现的结果如下:

select lic.license_number, * from Process process
left join Person p on process.person_id = p.id
left join License lic on lic.person_id = p.id;

  1. 我尝试过使用Join
  2. ```java
  3. final CriteriaBuilder builder = entityManager.getCriteriaBuilder();
  4. final CriteriaQuery<Process> criteria = builder.createQuery(Process.class);
  5. final Root<Process> rootSelect = criteria.from(Process.class);
  6. //我真的不知道如何连接rootSelect(Process表)与License表...中间有Person表..
  7. Join<Process, Person> personJoin = rootSelect.join("person");
  8. Join<License, Person> licenseJoin = rootSelect.join("person");

我还考虑使用子查询:

  1. final CriteriaBuilder builder = entityManager.getCriteriaBuilder();
  2. final CriteriaQuery<Process> criteria = builder.createQuery(Process.class);
  3. final Root<Process> rootSelect = criteria.from(Process.class);
  4. Subquery sub = criteria.subquery(String.class);
  5. Root subRoot = sub.from(License.class);
  6. //如何仅选择下面的字段'license_number'?
  7. sub.select(subRoot);
  8. sub.where(builder.equal(rootSelect.get("person").get("id"), subRoot.get("person")));

我将需要许可证号码来进行最后的筛选(where)。

在考虑我的根表是Process的情况下,最好的方法是什么?

  1. <details>
  2. <summary>英文:</summary>
  3. I&#39;m trying to get the license number from the person from the process table through criteria API.
  4. Basically from `Process -&gt; Person -&gt; License`
  5. However, Person table has a unidirectional OneToMany relationship with table License.
  6. So I have the following entities:

@Entity
@Table(name = "Process")
public class Process {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;

  1. @OneToOne(fetch = FetchType.EAGER)
  2. @JoinColumn(name = &quot;person_id&quot;)
  3. Person person;

}

@Entity
@Table(name = "Person")
public class Person {
@Id
@Column(name = "id",columnDefinition="INTEGER")
@GeneratedValue(strategy = GenerationType.IDENTITY)
Integer id;

  1. @OneToMany(fetch = FetchType.LAZY, mappedBy = &quot;person&quot;)
  2. List&lt;License&gt; licenses;

}

@Entity
@Table(name = "License")
public class License {
@Id
@Column(name = "id",columnDefinition="INTEGER")
@GeneratedValue(strategy = GenerationType.IDENTITY)
Integer id;

  1. @JoinColumn(name = &quot;person_id&quot;)
  2. @ManyToOne(fetch = FetchType.LAZY)
  3. Person person;
  4. String licenseNumber;

}

  1. In a native query, the result I would want to accomplish would be:

select lic.license_number, * from Process process
left join Person p on process.person_id = p.id
left join License lic on lic.person_id = p.id;

  1. I have tried with Join:

final CriteriaBuilder builder = entityManager.getCriteriaBuilder();
final CriteriaQuery<Process> criteria = builder.createQuery(Process.class);
final Root<Process> rootSelect = criteria.from(Process.class);

//I don't really know how to join rootSelect (Process table), with License table... having the table Person in middle..
Join<Process, Person> personJoin = rootSelect.join("person");
Join<License, Person> licenseJoin = rootSelect.join("person");

  1. and also considered using subquery:

final CriteriaBuilder builder = entityManager.getCriteriaBuilder();
final CriteriaQuery<Process> criteria = builder.createQuery(Process.class);
final Root<Process> rootSelect = criteria.from(Process.class);

Subquery sub = criteria.subquery(String.class);
Root subRoot = sub.from(License.class);
//How to select just the field 'license_number' below?
sub.select(subRoot);
sub.where(builder.equal(rootSelect.get("person").get("id"), subRoot.get("person")));

  1. I will need the license_number for a filter (where) at the end.
  2. What would be the best way to do such a filter, considering my root table is Process?
  3. </details>
  4. # 答案1
  5. **得分**: 1
  6. 严格来说,您不必将“Process”表与“license”表连接,而是必须按照以下方式连接“Process”与“Person”以及“Person”与“License”:
  7. ```java
  8. Join<Process, Person> personJoin = rootSelect.join("person", JoinType.INNER);
  9. Join<Person, License> licenseJoin = personJoin.join("licenses", JoinType.INNER);

建议使用元模型和实体,使用它们的话,连接将如下所示(元模型由EntityName_表示):

  1. Join<Process, Person> personJoin = rootSelect.join(Process_.person, JoinType.INNER);
  2. Join<Person, License> licenseJoin = personJoin.join(Person_.licenses, JoinType.INNER);

对我来说,最明显的好处是您可以自动完成元模型的属性,而使用字符串则增加了出错的机会。

我们添加了筛选条件:

  1. cq.where(cb.equal(licenseJoin.get("licenseNumber"), LICENSE_NUMBER));
  2. // cq.where(cb.equal(licenseJoin.get(License_.licenseNumber), LICENSE_NUMBER));
英文:

Strictly speaking, you don't have to join the Process tables with license, you have to join Process with Person and Person with License as follows:

  1. Join&lt;Process, Person&gt; personJoin = rootSelect.join(&quot;person&quot;,JoinType.INNER);
  2. Join&lt;Person, License&gt; licenseJoin = personJoin.join(&quot;licenses&quot;,JoinType.INNER);

It is recommended to use metamodels and entities, with them the Join would be as follows (the metamodel is represented by EntityName_):

  1. Join&lt;Process, Person&gt; personJoin = rootSelect.join(Process_.person,JoinType.INNER);
  2. Join&lt;Person, License&gt; licenseJoin = personJoin.join(Person_.licences,JoinType.INNER);

For me the clearest benefit is that you can autocomplete the properties of the metamodel, putting a string increases the chances that we are wrong.

We add the filter condition

  1. cq.where(cb.equal(licenceseJoin.get(&quot;licenseNumber&quot;),LICENSE_NUMBER));
  2. //cq.where(cb.equal(licenceseJoin.get(License_.licenseNumber),LICENSE_NUMBER));

huangapple
  • 本文由 发表于 2020年8月6日 06:48:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/63274545.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定