I want to know how to use JPA Criteria API to filter entity by related entity's foreign key.
Let's say i have two entities as the following:
public class Employee {
@Id
private Long id;
...
@ManyToOne
private Department department;
...
}
public class Department {
@Id
private Long id;
}
I want to query the employees under departments of ids (1,2,3).
I was able to do that using Hibernate's depricated criteria, And want to know how to do it using the JPA Criteria predicate without join (root.join) . It is logical that i don't need any join or subquery, as the desired result can be fetched from one table:
select e.* from employee e where e.department_id in (1,2,3)
** Update **
My problem was - as new for JPA Criteria and coming from the deprecated Hibernate Criteria - that I've used all APIs from the CriteriaBuilder such as (equal, notEqual, isNull, like, .....); And ,thus , used the CriteriaBuilder.In(experssion).in(values)
. But, as shown in the answer of @frank, I figured out that for the IN usage, I'll use Root.get(<attr>).in(<values>)
The CriteriaBuilder.in
also can be used but differently:
In<Object> inClause = criteriaBuilder.in(root.get(<attr>);
for (Long id : ids) {
inClause.value(id);
}
But, Of-course, the first solution is easier.
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();
It is logical in SQL, but in JPA you should do the Join to prevent queries from being launched to initialize the Department type objects.
It can be done, but I think it would be better to do it with a Join.
In the end, even if the table has the information, your JPA entities, which is what Criteria-api understands, does not have that ID, it has a reference to an object with that ID.
Although I do not recommend it, the implementation would be something like this:
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);
Activate the log traces to show the launched queries and think if it is worth throwing a query with a join or N queries without a join.
In order not to overload the memory you should establish the relations as lazy.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.