Can anybody give me some hints on how to put that kind of subquery in a CriteriaQuery? (I'm using JPA 2.0 - Hibernate 4.x)
SELECT a, b, c FROM tableA WHERE a = (SELECT d FROM tableB WHERE tableB.id = 3) - the second select will always get a single result or null.
Try something like the following example to create a subquery:
CriteriaQuery<Object[]> cq = cb.createQuery(Object[].class);
Root tableA = cq.from(TableA.class);
Subquery<String> sq = cq.subquery(TableB.class);
Root tableB = cq.from(TableB.class);
sq.select(tableB.get("d"));
sq.where(cb.equal(tableB.get("id"), 3));
cq.multiselect(
cb.get("a"),
cb.get("b"),
cb.get("c"));
cq.where(cb.equal(tableA.get("a"), sq));
List<Object[]> = em.createQuery(cq).getResultList();
Note the code has not been tested due to the lack of an IDE nearby.
You can use DetachedCriteria to represend the sub-query. Your code should look something like:
DetachedCriteria subCriteria = DetachedCriteria.forClass(TableB.class);
subCriteria.add(Property.forName("id").eq(3)); //WHERE tableB.id = 3
subCriteria.setProjection(Projections.property("d")); // SELECT d from
DetachedCriteria criteria = DetachedCriteria.forClass(getPersistentClass());
criteria.add(Property.forName("a").eq(subCriteria)); //a = (sub-query)
criteria.setProjection(Projections.property("a"); //SELECT a
criteria.setProjection(Projections.property("b"); //SELECT b
criteria.setProjection(Projections.property("c"); //SELECT c
return getHibernateTemplate().findByCriteria(criteria);
Related
I have a scenario where I need to get the row with maximum date. The SQL query for this would be
SELECT c.*
FROM course c
INNER JOIN
(SELECT moduleId ,MAX(endDate) AS max_date
FROM course
WHERE moduleId = 12345
GROUP BY moduleId
) customSelect
ON customSelect.moduleId = c.moduleId AND c.endDate = customSelect.max_date
WHERE c.moduleId = 12345
I need to convert this query to JPA using CriteriaBuilder.Since this isn't a direct entity join, rather a selection join to root entity, I'm having trouble to figure out how to join the custom select part to the root entity Course with below syntax:
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<Course> criteriaQuery = builder.createQuery(Course.class);
Root<Course> root = criteriaQuery.from(Course.class);
And then how to root.join(JoinType.INNER) to join customSelect part?
If someone can show some pointers to the syntax of of joining the root to a custom selection, that would be great.
Try this
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<Course> criteriaQuery = builder.createQuery(Course.class);
Root<Course> root = criteriaQuery.from(Course.class);
criteriaQuery.select(root).where(cb.equal(root.get(Course_.moduleId), 12345));
criteriaQuery.orderBy(cb.desc(r.get(Course_.endDate)));
TypedQuery<Course> query = em.createQuery(criteriaQuery);
query.setMaxResult(1);
Course result = query.getSingleResult();
Let's say, I have a query like
Select a.valA, b.valB
from tableA a join tableB b on a.joinCol = b.joinCol
where a.someCol = 1.
I want to execute it using Hibernate (and Spring Data) in one query to the database. I know, I can write just
Query query = em.createQuery(...);
List<Object[]> resultRows = (List<Object[]>)query.getResultList();
But my question would be - is it possible to do it in a typesafe way, using CriteriaQuery for example? The difficulty is, that, as you see, I need to select values from different tables. Is there some way to do this?
Simple example where an Employee has many to many relation to several jobs that he may have :
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<Tuple> criteria = builder.createTupleQuery();
Root<TableA> root = criteria.from(TableA.class);
Path<Long> qId = root.get("id");
Path<String> qTitle = root.get("title");
Join<TableA, TableB> tableTwo = root.join("joinColmn", JoinType.INNER);
criteria.multiselect(qId, qTitle, tableTwo);
List<Tuple> tuples = session.createQuery(criteria).getResultList();
for (Tuple tuple : tuples)
{
Long id = tuple.get(qId);
String title = tuple.get(qTitle);
TableB tableB= tuple.get(tableTwo);
}
but saw that there is an alternate answer here :
JPA Criteria API - How to add JOIN clause (as general sentence as possible)
I'd like to know how to make a query in JPA where content is not inside a "third table" responsible to make relationship manyToMany.
example:
SELECT id FROM A WHERE id NOT IN (SELECT id FROM A_B WHERE idB = #id)
In this case I have Table A, Table B, and the relationShip manytomany A_B
I tried with CriteriaQuery and subquery, but it didn't work. Actually, it returned none result.
Does somebody have any example for this case?
I got my solution!
I don't know if it is completely correct, so, if someone see an error, please let me know.
The end query, created by JPA become this:
select maingroup0_.GroupId as GroupId1_, maingroup0_.idGroupAttendanceType as idGroupA2_1_, maingroup0_.name as name1_ from TUnPbxGroup maingroup0_ where maingroup0_.GroupId not in (select maingroup1_.GroupId from TUnPbxGroup maingroup1_ inner join THolidayGroup listholida2_ on maingroup1_.GroupId=listholida2_.GroupId inner join THoliday holiday3_ on listholida2_.IdHoliday=holiday3_.IdHoliday where holiday3_.IdHoliday=2)
The code:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<MainGroup> query = cb.createQuery(MainGroup.class);
Root<MainGroup> root = query.from(MainGroup.class);
query.select(root);
Subquery<Long> subquery = query.subquery(Long.class);
Root<MainGroup> subRoot = subquery.from(MainGroup.class);
subquery.select(subRoot.<Long>get("id"));
Join<Holiday, Holiday> maingroups = subRoot.join("listHolidays");
subquery.where(cb.equal(maingroups.get("id"), holidayId));
query.where(cb.not(cb.in(root.get("id")).value(subquery)));
TypedQuery<MainGroup> typedQuery = em.createQuery(query);
List<MainGroup> result = typedQuery.getResultList();
Employee (table)
id - int
ctd_id - int
message - char
SELECT a.*
FROM Employee a left outer join
( select * from Employee where message = 23 ) b
on a.ctd_id = b.ctd_id
where a.message = 22 and b.id is null;
This is what i tried
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Employee> criteria = cb.createQuery(Employee.class);
Root<Employee> emp = criteria.from(Employee.class);
CriteriaQuery<Employee> sq = c.select(emp);
Subquery<Employee> sq2 = criteria.subquery(Employee.class);
Root<Employee> emp2 = sq2.from(Employee.class);
Join<Employee,Employee> sqEmp = emp2.join("ctd_id", JoinType.LEFT);
sq.select(sqemp).where(cb.equal(emp2.get("message"), cb.parameter(String.class, "23")));
sq.where(cb.in(path).value(sq2));
TypedQuery<Employee> q = em.createQuery(criteria);
List<Employee> employeess = q.getResultList()
But, i am not able to understand as to how i should apply a join on a subquery with where clause.
please help .
JPA does not support sub-queries in the FROM clause.
Either use SQL for your query, or rewrite it not to have a sub-query in the from clause, it doesn't look like you need it.
My Query is this:
query1 = select a.id from entity1 a where a.id in (:List1)
and not exists (select ex2 from entity2 ex2 where ex2.assignedId = a.id)
union
select ex.assignedId from entity2 ex ,entity3 pi
where ex.entity3Id = pi.id and ex.assignedId in (:List1)
and ex.assignedTypeId = :assignedTypeId and pi.processStatus = :status
and not exists
(select ex1.assignedId from entity2 ex1 , entity3 pi1
where ex1.entity3Id = pi1.id and ex1.assignedId = ex.assignedId
and ex1.assignedTypeId = :assignedTypeId
and pi1.processStatus <> :status);
and while trying to execute query,
Query existingIds=em.createQuery(query1); //With all parameters set
throws NullPointerException in line 87 of org.hibernate.hql.ast.ParameterTranslationsImpl
completely checked all the braces and parameters. The equivalent conversion works in mysql.
Can someone assist me in converting the query with CriteriaBuilder, finding it difficult to make the conversion.
Not sure if JPQL supports union operation at all. Are you putting this as NamedQuery or you are creating on the fly (entityManager.createQuery()) ?