Java – How to use JPA Criteria API when joining many tables


This is the further question to this:

How to use JPA Criteria API in JOIN

CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();

CriteriaQuery<Company> criteria = criteriaBuilder.createQuery( Company.class );
Root<Company> companyRoot = criteria.from( Company.class );
Join<Company,Product> products = companyRoot.join("dentist");
Join<Company, City> cityJoin = companyRoot.join("");//Company->Address->City-city
criteria.where(criteriaBuilder.equal(products.get("category"), "dentist"),      criteriaBuilder.equal(cityJoin.get("city"),"Leeds"));

A company has an address, inside the address there is City-pojo and Country-Pojo. How can I use it in JOIN? I tried to reference it with but I got the error message:

The attribute [] from the managed type
[EntityTypeImpl@1692700229:Company [ javaType: class
com.test.domain.Company descriptor:
RelationalDescriptor(com.test.domain.Company –>
[DatabaseTable(COMPANY)]), mappings: 16]] is not present.

Best Solution

If you use canonical Metamodel, you'll avoid this kind of errors. In your code you have misused the "dentist" keyword, that's probably the cause of your error, because "dentist" is not a field in Company entity.

However, looking at how you defined your class in the other question, the way to define that join using Metamodel is this:

SetJoin<Company,Product> products = companyRoot.join(Company_.products); 

As you can see, Metamodel avoids the use of strings, and so avoids a lot of runtime errors. If anyway you don't use Metamodel, try this:

SetJoin<Company,Product> products = companyRoot.join("products"); 

If you now want to add a predicate, i.e. something after the where, you'll write something like:

Predicate predicate = criteriaBuilder.equal(products.get(Product_.category), "dentist");

If you want to add a join for the City entity:

Join<Company, City> city = companyRoot.join(;
predicate = criteriaBuilder.and(predicate, criteriaBuilder.equal(city.get(City_.cityName), "Leeds");

(supposing that the field cityName is the correct field name for your city).