简体   繁体   中英

JPA criteria filter by related entity without join

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.

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