简体   繁体   English

Java - 标准 API - 单向 OneToMany

[英]Java - Criteria API - Unidirectional OneToMany

I'm trying to get the license number from the person from the process table through criteria API.我正在尝试通过标准 API 从流程表中的人员那里获取许可证号。 Basically from Process -> Person -> License基本上来自Process -> Person -> License

However, Person table has a unidirectional OneToMany relationship with table License.但是,Person 表与表 License 具有单向 OneToMany 关系。

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 = "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;
}

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.最后,我将需要 license_number 用于过滤器(在哪里)。

What would be the best way to do such a filter, considering my root table is Process?考虑到我的根表是 Process,执行这种过滤器的最佳方法是什么?

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:严格来说,您不必使用许可证加入 Process 表,您必须将 Process 加入 Person 和 Person with License,如下所示:

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

It is recommended to use metamodels and entities, with them the Join would be as follows (the metamodel is represented by EntityName_):建议使用元模型和实体,它们的连接如下(元模型由 EntityName_ 表示):

Join<Process, Person> personJoin = rootSelect.join(Process_.person,JoinType.INNER);
Join<Person, License> 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("licenseNumber"),LICENSE_NUMBER));
//cq.where(cb.equal(licenceseJoin.get(License_.licenseNumber),LICENSE_NUMBER));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM