I have below code which uses outdated Expression
Criteria criteria = getSession().createCriteria(TagSynonym.class);
criteria.add(Expression.like("title", "%"+piece+"%") );
criteria.setFirstResult(0);
criteria.setMaxResults(maxTagsInResult);
return criteria.list();
I want to achieve same with CriteriaBuilder. Below is what I tried, however it returns an empty array. Please guide what do I miss here. Also guide how to set limit on result.
EntityManager em = this.getEntityManager();
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery<TagSynonym> query = criteriaBuilder.createQuery(TagSynonym.class);
Root<TagSynonym> fromTagsSynonyms = query.from(TagSynonym.class);
Predicate likesTags = criteriaBuilder.equal(fromTagsSynonyms.get(TagSynonym_.title), "%"+piece+"%");
query.select(fromTagsSynonyms).where(likesTags);
return em.createQuery(query).getResultList();
You should use CriteriaBuilder#like() instead of CriteriaBuilder#equal(), to perform like matching.
Predicate likesTags = criteriaBuilder.like(fromTagsSynonyms.get(TagSynonym_.title), "%"+piece+"%");
For the rest your code is basically correct.
Related
I am using hibernate 5 (I am not familiar with hibernate, just started with it) and I want to perform a simple select query, after searching I found the following code to select an element by id:
CriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<Ord> query = cb.createQuery(MyClass.class);
Root<Ord> root = query.from(MyClass.class);
query.select(root);
query.where(cb.equal(root.get(MyClass.NUM),ordId));
Query<Ord> sessionQuery = session.createQuery(query);
return sessionQuery.getSingleResult();
I find it a heavy way to just get just one element.
The question is: Is the above the recommended/correct way to fetch data using hibernate (5)?
Thanks in advance,
JPQL provides us with a quicker and simpler implementation while using the Criteria API is more dynamic and robust.
public List<Student> findAllStudentsWithJpql() {
return session.createQuery("SELECT a FROM Student a", Student.class).getResultList();
}
You are using Criteria API
The Criteria API provides a dynamic approach for building JPA queries.
public List<Student> findAllStudentsWithCriteriaQuery() {
CriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<Student> cq = cb.createQuery(Student.class);
Root<Student> rootEntry = cq.from(Student.class);
CriteriaQuery<Student> all = cq.select(rootEntry);
TypedQuery<Student> allQuery = session.createQuery(all);
return allQuery.getResultList();
}
Above two methods are the common way in Hibernate.
Documentation - https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html
You can perform something like this...
#Autowired
private SessionFactory session;
Query<Your Class> query = session.getCurrentSession().createQuery("select * from <tableName>);
I am using javax CriteriaBuilder with CriteriaQuery like this:
CriteriaBuilder builder = getSession().getCriteriaBuilder();
CriteriaQuery<MyClazz> criteria = builder.createQuery(MyClazz.class);
Root<MyClazz> root = criteria.from(MyClazz.class);
Predicate predicate = builder.and(
builder.equal( root.get("attribute1"), "somestring");
);
criteria.select(root).where(predicate);
Query<MyClazz> query = getSession().createQuery(criteria);
The thing is that "attribute1" has length ~20. I dont want to compare full attribute1 length, i just want records WHERE attribute1 on position [5,16] equals "somsetring". Is there any way to achieve this?
I have two java objects.
User(every user has an index column)
Address( every address has an user_index column too)
I have a List of all the users index list, usersIndexList as given input and I want to fetch all of the address objects based on this usersIndexList. I found an example on another thread. And tried to follow it but it does not work.
JPA CriteriaBuilder - How to use "IN" comparison operator
My code:
List<String> usersIndexList= new ArrayList<String> ();
for (User u : usersList) {
usersIndexList.add(u.getIndex());
}
CriteriaBuilder criteriaBuilder = getEntityManager().getCriteriaBuilder();
CriteriaQuery<User> subQuery = criteriaBuilder.createQuery(User.class);
Root<User> fromUser= subQuery.from(User.class);
Expression<String> exp = fromUser.get("user_index");
Predicate predicate = exp.in(usersIndexList);
subQuery.where(predicate);
TypedQuery<User> query = getEntityManager().createQuery(subQuery);
return query.getResultList();
But this query is not returning the desired result :(
Can someone please tell me, where I am doing wrong or give me an alternate solutions if its possible via nativequery or namedquery or any other way
As per your question, you want to fetch all of the address objects based on this usersIndexList. But in your code you are selecting User objects, not the Address. Is my understanding Correct? If yes, then please change your root to Address as below -
List<String> usersIndexList= new ArrayList<String> ();
for (User u : usersList) {
usersIndexList.add(u.getIndex());
}
CriteriaBuilder criteriaBuilder = getEntityManager().getCriteriaBuilder();
CriteriaQuery<Address> subQuery = criteriaBuilder.createQuery(Address.class);
Root<Address> fromAddress= subQuery.from(Address.class);
Expression<String> exp = fromAddress.get("user_index");
Predicate predicate = exp.in(usersIndexList);
subQuery.where(predicate);
TypedQuery<Address> query = getEntityManager().createQuery(subQuery);
return query.getResultList();
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 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.