1

我想知道如何使用 JPA Criteria API 通过相关实体的外键过滤实体。

假设我有以下两个实体:

public class Employee {
    @Id
    private Long id;
    ...
    @ManyToOne
    private Department department;
    ...
}

public class Department {
    @Id
    private Long id;
}

我想查询ids(1,2,3)部门下的员工。

我能够使用 Hibernate 的废弃标准来做到这一点,并且想知道如何使用 JPA Criteria predicate without join (root.join)来做到这一点。我不需要任何连接或子查询是合乎逻辑的,因为可以从一个表中获取所需的结果:

select e.* from employee e where e.department_id in (1,2,3)

** 更新 **

我的问题是——对于 JPA 标准来说是新的,并且来自已弃用的 Hibernate 标准——我使用了 CriteriaBuilder 中的所有 API,例如 (equal, notEqual, isNull, like, .....); 并且,因此,使用了CriteriaBuilder.In(experssion).in(values). 但是,如@frank 的回答所示,我发现对于 IN 的使用,我将使用Root.get(<attr>).in(<values>)

CriteriaBuilder.in也可以使用但不同:

In<Object> inClause = criteriaBuilder.in(root.get(<attr>);
for (Long id : ids) {
    inClause.value(id);
}

但是,当然,第一个解决方案更容易。

4

2 回答 2

2
Set<Integer> departments = new HashSet<Integer>();
departments.add(1);
departments.add(2);
departments.add(3);

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Employee> cq = cb.createQuery(Employee.class);
Root<Employee> r = cq.from(Employee.class);
cq.select(r).where(r.get(Employee_.department).get(Department_.id).in(departments));
TypedQuery<Employee> query = em.createQuery(cq);
List<Employee> result = query.getResultList();
于 2020-08-28T08:09:45.837 回答
0

这在 SQL 中是合乎逻辑的,但在 JPA 中,您应该执行 Join 以防止启动查询以初始化 Department 类型对象。

可以做到,但我认为用Join来做会更好。

最后,即使表有信息,您的 JPA 实体(即 Criteria-api 所理解的)也没有该 ID,它具有对具有该 ID 的对象的引用。

虽然我不推荐它,但实现将是这样的:

CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Employee> cq = cb.createQuery(Employee.class);

Root<Employee> root = cq.from(Employee.class);

cq.where(root.get("department").in(listIds));
cq.select(root);

激活日志跟踪以显示已启动的查询,并考虑是否值得抛出一个有连接的查询或 N 个没有连接的查询。

为了不使内存过载,您应该将关系建立为惰性关系。

于 2020-08-28T08:03:16.567 回答