Hibernate query criteria for join between 3 tables - java

I have a sql query:
select * from A
INNER JOIN B
ON A.id = B.id
INNER JOIN C
ON B.id = C.id
INNER JOIN D
ON C.id = D.id
where D.name = 'XYZ'
and D.Sex = 'M'
I have been trying to come with hibernate query criteria for the above sql, but having problems. Could anybody help out.

Criteria c = session.createCriteria(A.class, "a");
.createAlias("a.b", "b")
.createAlias("b.c", "c")
.createAlias("c.d", "d")
.add(Restrictions.eq("d.sex", "M"))
.add(Restrictions.eq("d.name", "XYZ"));

On your question you want to perform a Cartesian Join, and this is not supported by Criteria, although you can do it with HQL as show below. There is a similar question here
With HQL query you could do something like:
select a from
A a,
B b,
C c
where
a.id = b.id and
c.id = b.id and
d.id = c.id and
d.name = 'XYZ' and
d.sex = 'M'
The query is used in a regular hibernate query:
Query query = session.createQuery(query); // <-- here you use the query above
List results = query.list();

Related

How to do a subquery on the same table by using JPA Hibernate?

Help me to convert the below mentioned query to Hibernate JPA.
Query query= entityManager.createQuery("Select a,b,c,d from table1 where d IN (Select d from table1 where a=1 and b=2");
Just giving an alias should work
entityManager.createQuery("Select a,b,c,d from table1 t
where t.d IN (Select r.d from table1 r where r.a=1 and r.b=2");

Are these SQL queries equivalent? And which is better or is there a better option?

I am working on a Spring web application that utilizes hibernate to connect to a DB2 database. I am try to optimize a service method that gets called may times during a wed service call by reducing the number of DB queries.
So my question is whether or not this query
SELECT DISTINCT a.* FROM TABLE_A a
LEFT JOIN TABLE_B b ON a.ID = b.FK_ID
LEFT JOIN TABLE_C c ON a.ID = c.FK_ID
LEFT JOIN TABLE_D d ON c.DATA_RQST_ID = d.ID
WHERE (b.REQUEST_ID = 1234 AND b.TYPE = 'TYPE_A')
OR (c.REQUEST_ID = 1234 AND (c.TYPE = 'TYPE_A' OR c.TYPE = 'TYPE_B'))
is equivalent/better then this query
SELECT * FROM TABLE_A a
WHERE a.ID IN
(
SELECT b.FK_ID FROM TABLE_B b
WHERE b.REQUEST_ID = 1234 AND eb.TYPE = 'TYPE_A'
)
OR a.ID IN
(
SELECT c.FK_ID FROM TABLE_C
WHERE ( c.REQUEST_ID = 1234 AND c.TYPE = 'TYPE_A' )
OR
(
c.TYPE = 'TYPE_B' AND c.REQUEST_ID IN
(
SELECT d.ID FROM TABLE_D d
WHERE d.REQUEST_ID = 1234 AND v.TYPE = 'TYPE_A'
)
)
)
or is there a better option?
Both queries seem to run about the same time (<50ms) but that may depend on the resulting data. I would need to test more to know for sure.
The point of these two queries is for one of them to replace three other queries where their resulting data is processed in Java to get the required data.
I will also have to be able to convert the SQL query to HQL. I was struggling to convert the first query.
I have a feeling that I maybe wasting my time since the java objects for tables B and C are a one-to-many relationship in the object for table A and they are load by hibernate anyway. Meaning I may not be saving anytime in the long run. Is my thinking here correct?
Thanks!
If I understand correctly, exists would be the best solution:
SELECT a.*
FROM TABLE_A a
WHERE EXISTS (SELECT 1
FROM TABLE_B b
WHERE a.ID = b.FK_ID AND b.REQUEST_ID = 1234 AND b.TYPE = 'TYPE_A'
) OR
EXISTS (SELECT 1
FROM TABLE_C c JOIN
TABLE_D d
ON c.DATA_RQST_ID = d.ID
WHERE a.ID = c.FK_ID AND
c.REQUEST_ID = 1234 AND
(c.TYPE IN ('TYPE_A', 'TYPE_B'))
);
One big gain is just in removing the select distinct.
Then for performance, you want indexes on table_b(fk_id, request_id, type_id) and table_c(fk_id, request_id, type, DATA_RQST_ID) and table_d(id).

Spring Data JPA #Query annotation, nativeQuery = true,

I have problem with my #Repository:
#Repository
public interface RekvZmRepository extends CrudRepository<RekvalZamestn, RekvalZamestnPk> {
#Query(value = "SELECT z.* FROM rek_zm d INNER JOIN proj_a a ON d.id = a.prj_idcislo"
+ " INNER JOIN proj_e e ON a.id = e.id"
+ " INNER JOIN rekv_z z ON d.id = z.id"
+ "WHERE d.id = ?1 AND a.id = ?2 AND e.id = ?3", nativeQuery = true)
public List<RekvalZamestn> getRekvOsOnDoh(Long dhzmrk, Long prj, Long prje);
}
When I run it, result is:
org.springframework.dao.InvalidDataAccessResourceUsageException: could not
extract ResultSet; SQL [n/a]; nested exception is
org.hibernate.exception.SQLGrammarException: could not extract ResultSet
When I run SQL it works, so for me it looks like problem is not with SQL but with my #Query.
Your query, in one-line format (condensing multiple spaces to one space for reasons of, erm, space), equates to
SELECT z.* FROM rek_zm d INNER JOIN proj_a a ON d.id = a.prj_idcislo INNER JOIN proj_e e ON a.id = e.id INNER JOIN rekv_z z ON d.id = z.idWHERE d.id = ?1 AND a.id = ?2 AND e.id = ?3
If you concatenate all the strings in one line like this, it becomes obvious that you are missing a space before the WHERE clause.
change SELECT z.* FROM to SELECT z FROM assuming RekvalZamestn class maps to table rekv_z.

Add count of child table to select from parent with hibernate criteria API

How can I execute this SQL query using the Hibernate Criteria API?
SELECT c.*, count(r.id) FROM COURSE c left join REFERRAL r on c.id = r.course_id group by c.id
Something like this seems close enough:
Criteria criteria = currentSession().createCriteria(Referral.class, "r");
criteria.createAlias("r.course", "course");
ProjectionList projections = Projections.projectionList();
projections.add(Projections.groupProperty("course.id"));
projections.add(Projections.count("r.id"));
return list(criteria
.setProjection(projections));

How to formulate a JOIN in a typed query?

I want to create a typed query.
TypedQuery<PubThread> query = em.createQuery(queryString, PubThread.class);
query.setParameter("threadId", threadId);
List<PubThread> otherPubThreads = query.getResultList();
In the queryString is the following SQL (currently without param and static selection values)
SELECT pt2 FROM pubthread pt2
JOIN pub_pubthread ppt2 ON pt2.id = ppt2.pubThreads_id
JOIN pub p2 ON ppt2.pups_id = p2.id
JOIN pubcategory pc2 ON p2.pubCategoryId = pc2.id
WHERE pt2.id != 1 and EXISTS (
SELECT DISTINCT(pt.id)
FROM pubthread pt
JOIN pub_pubthread ppt ON pt.id = ppt.pubThreads_id
JOIN pub p ON ppt.pups_id = p.id
JOIN pubcategory pc ON p.pubCategoryId = pc.id
WHERE pc2.id = pc.id and pt.id = 1
)
It does work, if I limit the String to a simple select: SELECT Distinct(pt2.id), pt2.name FROM pubthread pt2. As soon I add a JOIN line to it, it will complain. How do you properly query with JOINS in JPA? The error is:
org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token: ON near line 1, column 81 [SELECT pt2 FROM com.brayan.webapp.model.PubThread pt2 JOIN pub_pubthread ppt2 ON pt2.id = ppt2.pubThreads_id ]
Doubtless, a criteria query would be nicer. I accept that as part of the solution space.
When you call createQuery you have to write HQL but not SQL (your queryString is not HQL).
In HQL you have to join objects according to your mapping entities.
If you sill need SQL query use createNativeQuery method.
See documentation about how to create HQL query.
Got it. See below a fully example of joins. It consists of:
multiple joins (join-chaining)
a subquery
a predicate correlation/equation over join tables, other than the root table.
I also commented the obsolete code lines for other to see what a wrong approach.
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery mainQuery = criteriaBuilder
.createQuery(PubThread.class);
// 1) MainQuery
// Create the FROM
Root<PubThread> rootPubThread = mainQuery.from(PubThread.class);
// Create the JOIN from the first select: join-chaining. You only need the return for ordering. e.g. cq.orderBy(cb.asc(categoryJoin.get(Pub_.title)));
Join<Pub, PubCategory> categoryJoin = rootPubThread.join(PubThread_.pups).join(Pub_.pubCategory);
// Create the WHERE
mainQuery.where(criteriaBuilder.not(criteriaBuilder.equal(rootPubThread.get(PubThread_.id), threadId)));
// Create the SELECT, at last
mainQuery.select(rootPubThread).distinct(true);
// 2) Subquery
Subquery<PubThread> subquery = mainQuery.subquery(PubThread.class);
Root<PubThread> rootPubThreadSub = subquery.from(PubThread.class);
//subquery.where(criteriaBuilder.equal(rootPubThread.get(PubThread_.id), threadId));
Join<Pub, PubCategory> categoryJoinSub = rootPubThreadSub.join(PubThread_.pups).join(Pub_.pubCategory);
subquery.select(rootPubThreadSub);
//Predicate correlatePredicate = criteriaBuilder.equal(rootPubThreadSub.get(PubThread_.id), rootPubThread);
Predicate correlatePredicate = criteriaBuilder.and(
//criteriaBuilder.equal(rootPubThreadSub.get(PubThread_.id), rootPubThread),
criteriaBuilder.equal(categoryJoinSub.get(PubCategory_.id), categoryJoin.get(PubCategory_.id)),
criteriaBuilder.equal(rootPubThreadSub.get(PubThread_.id), threadId)
);
subquery.where(correlatePredicate);
//Predicate correlatePredicate = criteriaBuilder.equal(rootPubThreadSub.get(PubThread_.id), rootPubThread);
Predicate mainPredicate = criteriaBuilder.and(
criteriaBuilder.not(criteriaBuilder.equal(rootPubThread.get(PubThread_.id), threadId)),
criteriaBuilder.exists(subquery)
);
//cq.where(criteriaBuilder.exists(subquery));
mainQuery.where(mainPredicate);

Categories