如何解决JPA标准按相关实体过滤,无需连接
我想知道如何使用JPA Criteria API通过相关实体的外键过滤实体。
假设我有以下两个实体:
public class Employee {
@Id
private Long id;
...
@ManyToOne
private Department department;
...
}
public class Department {
@Id
private Long id;
}
我想查询id为(1,2,3)的部门的员工。
我能够使用Hibernate的描述标准来做到这一点,并且想知道如何使用JPA Criteria谓词无需连接(root.join)来做到这一点。不需要任何联接或子查询是合乎逻辑的,因为可以从一个表中获取所需结果:
select e.* from employee e where e.department_id in (1,3)
**更新**
我的问题是-对于JPA Criteria来说是新的,并且来自不赞成使用的Hibernate Criteria-我使用了CriteriaBuilder中的所有API,例如(等于,notEqual,isNull,例如.....);然后使用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);
}
但是,当然,第一个解决方案更容易。
解决方法
在SQL中这是合乎逻辑的,但是在JPA中,您应该执行Join来防止启动查询以初始化Department类型对象。
这是可以做到的,但我认为使用Join会更好。
最后,即使表包含信息,Criteria-api理解的JPA实体也没有该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个不带有连接的查询。
为了不使内存过载,您应该将关系建立为惰性。
,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();
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。