SQL QUERY:
SELECT SUM(IF(table.type='type1', 1, 0)) as type1,SUM(IF(table.type='type2', 1, 0)) as type2 from table;
How to write same query in criteria builder like below:
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Object[]> criteria = builder.createQuery( Object[].class );
Root<Table> root = criteria.from( Table.class );
criteria.multiselect(builder.sum())
I am unable to place if condition in criteria builder.
Note: there is bean class for Table.
Thanks in advance.
Apparently hibernate criteria does not support IF. I would consider just making 2 queries with criteria or using HQL or just native SQL.
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();
Before Hibernate 5 deprecated the Criteria class, you could add restrictions to a Criteria to act as a constraint, and projections to act as select statements, like so
Criteria criteria = session.createCriteria(T.class)
.add(Restrictions.or(Restrictions.eq(property, constraintValue)
.set(Projection(Projections.projectionList()
.add(Projections.property(selectValue)));
But, since you now need to use CriteriaQuery like so,
CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
CriteriaQuery<T> criteriaQuery = criteriaBuilder.createQuery(T.class);
Root<T> root = criteriaQuery.from(T.class);
criteriaQuery.select(root);
Query<T> query = session.createQuery(criteriaQuery);
However I have been unable to figure out how to add certain things which are required in SQL statements, mainly because searching for documentation tends to wind up on documentation about Criteria, due to the naming similarity.
So, how can I recreate a simple query, like the one below, using CriteriaQuery?
SELECT selectValue
FROM tables.T
WHERE property = constraintValue
Source.
Has multiple examples, but turns out that the simple select statement we were trying to recreate can be done like so:
CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
CriteriaQuery<SELECTVALUETYPE> criteriaQuery = criteriaBuilder.createQuery(SELECTVALUETYPE.class);
Root<PARENTCLASS> root = criteriaQuery.from(PARENTCLASS.class);
criteriaQuery.select(root);
criteriaQuery.where(criteriaBuilder.equal(root.get(property), constraintValue));
Query<SELECTVALUETYPE> query = session.createQuery(criteriaQuery);
Note that this is a generic answer, and won't actually run. The reason being, SELECTVALUETYPE needs to be replaced with the data type of selectValue.
For example, CriteriaQuery might become:
String selectValue -> CriteriaQuery
T selectValue -> CriteriaQuery
Therefore, a working example for the statement
Select name
From Users
Where ID = 1
Could be expressed with the following block
int ID = 1;
CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
CriteriaQuery<String> criteriaQuery = criteriaBuilder.createQuery(String.class);
Root<User> root = criteriaQuery.from(User.class);
criteriaQuery.select(root.get("name");
criteriaQuery.where(criteriaBuilder.equal(root.get("ID"), ID));
Query<String> query = session.createQuery(criteriaQuery);
List<String>results = query.getResultList();
for(String name : results){
System.out.println("Name: " + name);
}
I am very new in hibernate I have an MySQL Query and I want to achive same output using Hibernate criteria
MySQL Query:
SELECT *,
(case when status = 'Active'
then 'Can Login'
else 'Not able to login' end) as LoginStatus
FROM UserLoginTable;
My Hibernate Code:
SessionFactory sessionFactory = HibernateUtility.getSessionFactory();
Session session_hiber = sessionFactory.openSession();
session_hiber.beginTransaction();
Criteria criteria;
criteria = session_hiber.createCriteria(UserLoginTable.class);
List<UserLoginTable> myUserList = (List<UserLoginTable>)
criteria.list();
How I can add the Case criteria in the above code.
Is there any way ?
Thanks
Although I did not test this snippet, you may try to use CriteriaBuilder something like this:
CriteriaBuilder cb = session_hiber.getCriteriaBuilder();
cb.selectCase()
.when(cb.equal(path.get("status"), "Active"), "Can Login")
.otherwise("Not able to login")
.alias("LoginStatus");
Some help/info can be found here:
CASE statement in HQL or Criteria
Using the 'case...when...then...else...end' construct in the 'having' clause in JPA criteria query
https://docs.oracle.com/javaee/6/api/javax/persistence/criteria/CriteriaBuilder.html
I am trying to write following SQL query using JPA Criteria API
SELECT * FROM roles WHERE roles.name IN (SELECT users.role FROM users where name="somename");
and it is a bit to much for me (I have just started learing Criteria API). I got something like this:
CriteriaBuilder criteriaBuilder = manager.getCriteriaBuilder();
CriteriaQuery<RoleEntity> criteriaQuery = criteriaBuilder.createQuery(RoleEntity.class);
Root<RoleEntity> root = criteriaQuery.from(RoleEntity.class);
Subquery<UserEntity> subquery = criteriaQuery.subquery(UserEntity.class);
Root<UserEntity> subqueryRoot = subquery.from(UserEntity.class);
subquery.where(criteriaBuilder.equal(subqueryRoot.get(UserEntity_.username), username));
subquery.select(subqueryRoot);
And I have no idea how to put it all together.
Best regards,
Bartek
Fellow JPA learner here. Here's my attempt at setting it up:
// Get the criteria builder from the entity manager
CriteriaBuilder cb = manager.getCriteriaBuilder();
// Create a new criteria instance for the main query, the generic type indicates overall query results
CriteriaQuery<RoleEntity> c = cb.createQuery(RoleEntity.class);
// Root is the first from entity in the main query
Root<RoleEntity> role = criteriaQuery.from(RoleEntity.class);
// Now setup the subquery (type here is RETURN type of subquery, should match the users.role)
Subquery<RoleEntity> sq = cb.subquery(RoleEntity.class);
// Subquery selects from users
Root<UserEntity> userSQ = sq.from(UserEntity.class);
// Subquery selects users.role path, NOT the root, which is users
sq.select(userSQ.get(UserEntity_.role))
.where(cb.equal(userSQ.get(UserEntity_.username), username)); // test for name="somename"
// Now set the select list on the criteria, and add the in condition for the non-correlated subquery
c.select(role)
.where(cb.in(role).value(sq)); // can compare entities directly, this compares primary key identities automatically
Hopefully that helps!
I am implementing "Advanced Search" kind of functionality for an Entity in my system such that user can search that entity using multiple conditions(eq,ne,gt,lt,like etc) on attributes of this entity. I am using JPA's Criteria API to dynamically generate the Criteria query and then using setFirstResult() & setMaxResults() to support pagination. All was fine till this point but now I want to show total number of results on results grid but I did not see a straight forward way to get total count of Criteria query.
This is how my code looks like:
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Brand> cQuery = builder.createQuery(Brand.class);
Root<Brand> from = cQuery.from(Brand.class);
CriteriaQuery<Brand> select = cQuery.select(from);
.
.
//Created many predicates and added to **Predicate[] pArray**
.
.
select.where(pArray);
// Added orderBy clause
TypedQuery typedQuery = em.createQuery(select);
typedQuery.setFirstResult(startIndex);
typedQuery.setMaxResults(pageSize);
List resultList = typedQuery.getResultList();
My result set could be big so I don't want to load my entities for count query, so tell me efficient way to get total count like rowCount() method on Criteria (I think its there in Hibernate's Criteria).
Thanks Vladimir!
I took your idea and used separate count query to use my existing array of predicates in it. Final implementation looks like this:
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Brand> cQuery = builder.createQuery(Brand.class);
Root<Brand> from = cQuery.from(Brand.class);
CriteriaQuery<Brand> select = cQuery.select(from);
.
.
//Created many predicates and added to **Predicate[] pArray**
.
.
CriteriaQuery<Long> cq = builder.createQuery(Long.class);
cq.select(builder.count(cq.from(Brand.class)));
// Following line if commented causes [org.hibernate.hql.ast.QuerySyntaxException: Invalid path: 'generatedAlias1.enabled' [select count(generatedAlias0) from xxx.yyy.zzz.Brand as generatedAlias0 where ( generatedAlias1.enabled=:param0 ) and ( lower(generatedAlias1.description) like :param1 )]]
em.createQuery(cq);
cq.where(pArray);
Long count = em.createQuery(cq).getSingleResult();
.
.
select.where(pArray);
.
.
// Added orderBy clause
TypedQuery typedQuery = em.createQuery(select);
typedQuery.setFirstResult(startIndex);
typedQuery.setMaxResults(pageSize);
List resultList = typedQuery.getResultList()
Though this is working fine but still I am not sure why I have to write
em.createQuery(cq);
to get it working. Any Idea?
Why don't you just use count?
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Long> cQuery = builder.createQuery(Long.class);
Root<Brand> from = cQuery.from(Brand.class);
CriteriaQuery<Long> select = cQuery.select(builder.count(from));
.
.
//Created many predicates and added to **Predicate[] pArray**
.
.
select.where(pArray);
// Added orderBy clause
TypedQuery<Long> typedQuery = em.createQuery(select);
typedQuery.setFirstResult(startIndex);
//typedQuery.setMaxResults(pageSize);
// here is the size of your query
Long result = typedQuery.getSingleResult();
If you're using Hibernate as your JPA-Provider have a look at projections, especially Projections.rowCount().
You might have to execute the query twice though, first get the count then get the results.
Note that for plain JPA you might need some other approach.
I guess both of the answers work. But none of them is optimal. The problem with ThinkFloyd's answer is that createQuery is used two times. And Vladimir Ivanov has created two instances of CriteriaQuery which I think is unnecessary.
val cb = entityManager.criteriaBuilder
val cq = cb.createQuery(ManualQuery::class.java)
val manualQuery = cq.from(ManualQuery::class.java)
val predicates = ArrayList<Predicate>()
/*
predications.....
*/
cq.select(manualQuery)
.where(*predicates.toTypedArray())
.orderBy(cb.desc(manualQuery.get<ZonedDateTime>("createdDate")))
val query = entityManager.createQuery(cq)
// total rows count
val count = query.resultList.size
val indexedQuery = query
.setFirstResult((currentPage - 1) * pageSize)
.setMaxResults(itemsPerPage)
Doing go it works. And it is done in Kotlin. You do it the same way in Java.