Gazeciarz
Gazeciarz

Reputation: 525

JPA Criteria - fetch with where clause

I have following query which is working fine:

public ContractorContractor findContractorByName(String contractorName) {
   CriteriaBuilder builder = em.getCriteriaBuilder();
   CriteriaQuery<ContractorContractor> query = builder.createQuery(ContractorContractor.class);
   Root<ContractorContractor> root = query.from(ContractorContractor.class);
   query.select(root).distinct(true);

   Predicate namePredicate = builder.like(root.get(ContractorContractor_.name), contractorName);
   query.where(builder.and(namePredicate));

   return em.createQuery(query).getSingleResult();
}

Above query gives me single contractor by name or throws exception. Now I would like to do same thing but get more informations about contractor (add the fetch to another child of contractor) but with following query I do not get result (org.springframework.dao.EmptyResultDataAccessException: No result found for query is thrown). Query with fetch:

public ContractorContractor findContractorByName(String contractorName) {
   CriteriaBuilder builder = em.getCriteriaBuilder();
   CriteriaQuery<ContractorContractor> query = builder.createQuery(ContractorContractor.class);
   Root<ContractorContractor> root = query.from(ContractorContractor.class);
   root.fetch(ContractorContractor_.countries);
   query.select(root).distinct(true);

   Predicate namePredicate = builder.like(root.get(ContractorContractor_.name), contractorName);
   query.where(builder.and(namePredicate));

   return em.createQuery(query).getSingleResult();
}

Can anybody tell me what I am doing wrong and why in above query?

Upvotes: 3

Views: 2352

Answers (1)

8hZWKA
8hZWKA

Reputation: 455

It appears that you have accidentally limited the domain of your query by adding a inner fetch join with the addition of the following statement:

root.fetch(ContractorContractor_.countries);

As per JPA 2.1, JSR 338, section 6.5.4

[...] A fetch join has the same join semantics as the corresponding inner or outer join [...]

Thus changing the implicit inner fetch join (JoinType.INNER) to an (outer) left fetch join should solve your problem:

root.fetch(ContractorContractor_.countries, JoinType.LEFT);

This side effect might seem a little unexpected which is probably why the authors of the specification added the following comment (although in context with standard joins, section 4.4.7):

Application developers should use caution in defining identification variables because the domain of the query can depend on whether there are any values of the declared type.

Upvotes: 2

Related Questions