Criteria JPA 2 with 3 tables
Each join takes you from the leftish type parameter to the rightish one. So, the details
join of my code (second line) starts from fromUpdates
, that is a Path<Update>
, and creates something which is behind the scenes also a Path<Detail>
. From that, you can build other joins. Try this (code not tested):
Root<Update> fromUpdates = query.from(Update.class);
Join<Update, Detail> details = fromUpdates.join("details");
Join<Detail, Associate> associate = details.join("associate");
List<Predicate> conditions = new ArrayList();
conditions.add(builder.equal(associate.get("associateId"), associateId));
conditions.add(builder.isNull(details.get("ack_date")));
TypedQuery<Update> typedQuery = em.createQuery(query
.select(fromUpdates)
.where(conditions.toArray(new Predicate[] {}))
.orderBy(builder.asc(fromUpdates.get("updateId")))
.distinct(true)
);
JPA Critera API Join 3 Tables get 1 Type
Start with a Root
of Employees and make a chain of joins:
CriteriaQuery<Employee> query = cb.createQuery(Employee.class);
Root<Employee> employee = query.from(Employee.class);
Join<Employee, Contract> contractJoin = employee.join("contracts"); // assuming that Employee has a collection property named contracts
Join<Contract, Company> companyJoin = contractJoin.join("company");
This is the correct Awnser with the following addition:
The Types "Employee" and "Company" have to have a field "companies" / "employees" with the @JoinTable annotation like follows:
Employee:
...
@OneToMany
@JoinTable(name="Contract" ...)
private List<Company> companies;
...
Company
...
@OneToMany
@JoinTable(name="Contract" ...)
private List<Employee> employees;
...
The "@JoinTable" annotation prevents hibernate to create a relation table on its own.
See the comments for more info.
Hibernate CriteriaBuilder to join multiple tables
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery query = cb.createQuery(/* Your combined target type, e.g. MyQueriedBuildDetails.class, containing buildNumber, duration, code health, etc.*/);
Root<BuildDetails> buildDetailsTable = query.from(BuildDetails.class);
Join<BuildDetails, CopyQualityDetails> qualityJoin = buildDetailsTable.join(CopyQualityDetails_.build, JoinType.INNER);
Join<BuildDetails, DeploymentDetails> deploymentJoin = buildDetailsTable.join(DeploymentDetails_.build, JoinType.INNER);
Join<BuildDetails, TestDetails> testJoin = buildDetailsTable.join(TestDetails_.build, JoinType.INNER);
List<Predicate> predicates = new ArrayList<>();
predicates.add(cb.equal(buildDetailsTable.get(BuildDetails_.buildNumber), "1.0.0.1"));
predicates.add(cb.equal(buildDetailsTable.get(BuildDetails_.projectName), "Tera"));
query.multiselect(buildDetails.get(BuildDetails_.buildNumber),
buildDetails.get(BuildDetails_.buildDuration),
qualityJoin.get(CodeQualityDetails_.codeHealth),
deploymentJoin.get(DeploymentDetails_.deployedEnv),
testJoin.get(TestDetails_.testStatus));
query.where(predicates.stream().toArray(Predicate[]::new));
TypedQuery<MyQueriedBuildDetails> typedQuery = entityManager.createQuery(query);
List<MyQueriedBuildDetails> resultList = typedQuery.getResultList();
I assume you built the JPA metamodel for your classes. If you don't have the metamodel or you simply don't want to use it, just replace BuildDetails_.buildNumber
and the rest with the actual names of the column as String
, e.g. "buildNumber"
.
Note that I could not test the answer (was also writing it without editor support), but it should at least contain everything you need to know to build the query.
How to build your metamodel? Have a look at hibernate tooling for that (or consult How to generate JPA 2.0 metamodel? for other alternatives). If you are using maven it can be as simple as just adding the hibernate-jpamodelgen
-dependency to your build classpath. As I do not have any such project now available I am not so sure about the following (so take that with a grain of salt). It might suffice to just add the following as dependency:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>5.3.7.Final</version>
<scope>provided</scope> <!-- this might ensure that you do not package it, but that it is otherwise available; untested now, but I think I used it that way in the past -->
</dependency>
JPA Criteria API join on 3 tables and some null elements
Finally got the solution : to fetch all the corresponding results, I had to add the type of the join which would be left join, since I wanted to fetch all ParentObjects regardless of owning childOne or ChildTwo objects.
final Join<ParentObject, ChildOne> joinchildOne =
root.join("childOne", JoinType.LEFT);
final Join<ParentObject, ChildTwo > joinchildTwo =
root.join("childTwo", JoinType.LEFT);
How to use JPA Criteria API when joining many tables
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");
criteria.where(predicate);
If you want to add a join
for the City entity:
Join<Company, City> city = companyRoot.join(Company_.city);
predicate = criteriaBuilder.and(predicate, criteriaBuilder.equal(city.get(City_.cityName), "Leeds");
criteria.where(predicate);
(supposing that the field cityName is the correct field name for your city).
How to join 3 table using hibernate criteria?
You just create a root for every entity and add the condition to the where clause. Something like this:
Root<Parent> parent = criteriaQuery.from(Parent.class);
Root<ParentChildMapping> mapping = criteriaQuery.from(ParentChildMapping.class);
Root<Child> child = criteriaQuery.from(Child.class);
criteriaQuery.select(parent.get("parentId"));
criteriaQuery.where(
criteriaBuilder.and(
criteriaBuilder.equal(parent.get("parentId"), mapping.get("mappingParentId")),
criteriaBuilder.equal(child.get("childId"), mapping.get("mappingChildId")),
criteriaBuilder.equal(child.get("childName"), "abc")
)
);
Related Topics
How to Upload a Document to Sharepoint With Java
Spring Boot @Autowired Environment Throws Nullpointerexception
Simplifying the If-Else Condition Using Java Functional Style Programming
How to Avoid Thread.Sleep in Unit Tests
Batch Inserts Using JPA Entitymanager
How to Remove All Special Character in a String Except Dot and Comma
How to Test If Json Collection Object Is Empty in Java
Spring Boot Not Recognizing Application.Properties File
Getting Url Parameter in Java and Extract a Specific Text from That Url
In Activity.Oncreate(), Why Does Intent.Getextras() Sometimes Return Null
How to Run Selenium Webdriver in the Background
How to Convert a Byte to Its Binary String Representation
How to Find Max Date in List<Object>
Unable to Deploy Spring Boot 2 Application Due to Hikaripool Exception During Pool Initialization
Type Safety: Unchecked Cast from Object to Arraylist<Myvariable>
How to Split Single Row into Multiple Rows in Spark Dataframe Using Java
Spring Kafka - How to Reset Offset to Latest With a Group Id