Java – Criteria API – 单向 OneToMany

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

Java - Criteria API - Unidirectional OneToMany

问题

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

我正试图通过Criteria API从流程表中获取人员的许可证号码。基本上是从`Process -> Person -> License`。

然而,Person表与License表之间有一个单向的OneToMany关系。

所以我有以下的实体类:

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

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

}

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

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

}

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

@JoinColumn(name = "person_id")
@ManyToOne(fetch = FetchType.LAZY)
Person person;

String licenseNumber;

}


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

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;


我尝试过使用Join:

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

//我真的不知道如何连接rootSelect(Process表)与License表...中间有Person表..
Join<Process, Person> personJoin = rootSelect.join("person");
Join<License, Person> licenseJoin = rootSelect.join("person");

我还考虑使用子查询:

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);
//如何仅选择下面的字段'license_number'?
sub.select(subRoot);
sub.where(builder.equal(rootSelect.get("person").get("id"), subRoot.get("person")));

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

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


<details>
<summary>英文:</summary>

I&#39;m trying to get the license number from the person from the process table through criteria API.
Basically from `Process -&gt; Person -&gt; License`

However, Person table has a unidirectional OneToMany relationship with table License.

So I have the following entities:

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

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

}

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

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

}

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

@JoinColumn(name = &quot;person_id&quot;)
@ManyToOne(fetch = FetchType.LAZY)
Person person;

String licenseNumber;

}


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;


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");


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")));


I will need the license_number for a filter (where) at the end.

What would be the best way to do such a filter, considering my root table is Process?

</details>


# 答案1
**得分**: 1

严格来说,您不必将“Process”表与“license”表连接,而是必须按照以下方式连接“Process”与“Person”以及“Person”与“License”:

```java
Join<Process, Person> personJoin = rootSelect.join("person", JoinType.INNER);
Join<Person, License> licenseJoin = personJoin.join("licenses", JoinType.INNER);

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

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

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

我们添加了筛选条件:

cq.where(cb.equal(licenseJoin.get("licenseNumber"), LICENSE_NUMBER));
// 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:

Join&lt;Process, Person&gt; personJoin = rootSelect.join(&quot;person&quot;,JoinType.INNER);
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_):

Join&lt;Process, Person&gt; personJoin = rootSelect.join(Process_.person,JoinType.INNER);
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

cq.where(cb.equal(licenceseJoin.get(&quot;licenseNumber&quot;),LICENSE_NUMBER));
//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:

确定