Hi guys I'm trying to use criteria along with pagination but my code isn't working, here it is :
public Page<Person> getAuthorizationsTest() {
PageRequest pageRequest = new PageRequest(1, 5);
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery<Person> queryBase = criteriaBuilder.createQuery(Person.class);
Root<Person> root = queryBase.from(Person.class);
List<Predicate> queryConditions = new ArrayList<>();
Predicate predicate = criteriaBuilder.like(root.get("name"), "%[myValue]%");
queryConditions.add(predicate);
queryBase.where(queryConditions.toArray(new Predicate[]{}));
TypedQuery<Person> query = em.createQuery(queryBase);
List<Person> list = query.getResultList();
Page<Person> authorizations = new PageImpl<Person>(list, pageRequest, list.size());
return authorizations;
}
All seems fine, but when I execute it, I receive a list Page with all the results and not only the ones specified in my pageRequest
What am I doing wrong ?
Predicate array and where clause looking properly defined. In these lines:
Predicate predicate = criteriaBuilder.like(root.get("name"),
"%[myValue]%");
queryConditions.add(predicate);
queryBase.where(queryConditions.toArray(new Predicate[]{}));
TypedQuery<Person> query = em.createQuery(queryBase);
Just a reminder. Maybe you need criteriaBuilder.equal instead of criteriaBuilder.like. If you sure what you did you can omitted this reminder.
You need to change following lines like:
query.setFirstResult(Math.toIntExact(pageRequest.getOffset()));
query.setMaxResults(pageRequest.getPageSize());
return new PageImpl<Person>(query.getResultList(), pageRequest, getTotalCount(criteriaBuilder, queryConditions));
Then add getTotalCount method for the sake of consistency.
private Long getTotalCount(CriteriaBuilder criteriaBuilder, Predicate[] predicateArray) {
CriteriaQuery<Long> criteriaQuery = criteriaBuilder.createQuery(Long.class);
Root<T> root = criteriaQuery.from(entityType);
criteriaQuery.select(criteriaBuilder.count(root));
criteriaQuery.where(predicateArray);
return entityManager.createQuery(criteriaQuery).getSingleResult();
}
You are not using a paging request :
List list = query.getResultList();
This query will always query for all the results which is very inefficient.
Instead, you should do this the Spring way ie you should use a repository interface that extends a PagingAndSortingRepository (such as the JpaRepository interface).
Then simply use a method to paginate your results such as findAll as stated in the documentation :
PagingAndSortingRepository<User, Long> repository = // … get access to a bean
Page<User> users = repository.findAll(new PageRequest(1, 20));
Related
I am stuck with this problem
I want to create Criteria Query which translates to
select * from table
where (col1,col2) in ((val1,val2),(val2,val3),....)
I understood how to create it for IN clause on single column
But I want to have IN clause on combination of two columns where values in IN clause is list of tuple of values for these two columns.
Kindly suggest.
EntityManager entityManager;
public List<YourEntity> getEntitiesByParams(Map<Field1Class, Field2Class> params) {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<YourEntity> query = cb.createQuery(YourEntity.class);
Root<YourEntity> root = query.from(YourEntity.class);
final List<Predicate> predicates = new ArrayList<>();
for(Entry<Field1Class, Field2Class> entry : params.entrySet()) {
Predicate predicate1 = cb.equal(root.get("field1"), params.getKey());
Predicate predicate2 = cb.equal(root.get("field2"), params.getValue());
predicates.add(
cb.and(predicate1, predicate2)
);
}
query.select(root)
.where(
cb.or(predicates.toArray(new Predicate[predicates.size()]))
);
return entityManager.createQuery(query).getResultList();
}
I want to implement Hibernate query with OrderBy clause. I tried this:
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<OrdersModel> query = builder.createQuery(OrdersModel.class);
Root<OrdersModel> root = query.from(OrdersModel.class);
query.select(root).orderBy(root.get("added"));
Query<OrdersModel> q = session.createQuery(query);
cdList = q.getResultList();
But I have to cast the .orderBy like this query.select(root).orderBy((List<javax.persistence.criteria.Order>) root.get("added"));
Do you know what is the proper way to implement this?
I tried also this:
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<OrdersModel> query = builder.createQuery(OrdersModel.class);
Root<OrdersModel> root = query.from(OrdersModel.class);
query.select(root);
query.orderBy(builder.desc(root.get("added")));
Query<OrdersModel> q = session.createQuery(query).setMaxResults(5);
cdList = q.getResultList();
But the rows order are not displayed properly. The list is not properly sorted.
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();
Code:
List<Predicate> conditionsList = new ArrayList<Predicate>();
Predicate onStart = criteriaBuilder.greaterThanOrEqualTo(criteriaRoot.get("insertDateTime"), startTradeDate);
Predicate onEnd = criteriaBuilder.lessThanOrEqualTo(criteriaRoot.get("insertDateTime"), endTradeDate);
conditionsList.add(onStart);
conditionsList.add(onEnd);
CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder();
CriteriaQuery<MyClass> criteriaQuery =
criteriaBuilder.createQuery(MyClass.class);
Root<MyClass> criteriaRoot = criteriaQuery.from(MyClass.class);
criteriaQuery.select(criteriaRoot).where(conditionsList);
The last line above doesn't compile because its expecting the conditionsList object to be a List of Boolean not list of Predicate.
Please advise me on the correct way of adding predicates above to the hibernate criteria?
Convert the List<Predicate> into an array Predicate[] like this:
criteriaQuery.select(criteriaRoot).where(conditionsList.toArray(new Predicate[] {}));
Lets say you have two Entities Cats and Licks. Each has a list of the other. How do you write JPA to find one, given the id of the other.
My question is this: why not make this more simple? This interface is confusing... but here is how you do it anyway.
#PersistenceContext
protected EntityManager em;
#Test
public void testFindCatsByLickId() throws Exception
{
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery cq = cb.createQuery();
Root<Cat> cats = cq.from( Cat.class );
Root<Lick> licks = cq.from( Lick.class );
ListJoin<Cat, Lick> joinCatL = cats.join(Cat_.lickList);
// just creating the following ListJoin object will cause this query to fail!
// ListJoin<Lick, Cat> joinLCat = lick.join(Lick_.catList);
Predicate p = cb.and(
cb.equal(licks.get(Lick_.lickId), new Integer(2))
, cb.equal(licks, joinCatL)
);
cq.select(cats).where(p);
TypedQuery query = em.createQuery(cq);
List<Cat> list = query.getResultList();
assertList( list );
assertTrue(null != list && ! list.isEmpty() );
}
The criteria API is useful when you need to dynamically compose a query from a set of optional search criteria. In this case, using JPQL leads to much simpler and more readable code:
String jpql = "select cat from Lick lick inner joinlick.cats cat where lick.id = :lickId";
List<Cat> cats = em.createQuery(jpql, Cat.class).setParameter("lickId", 2)
.getResultList();
Or even simpler, without any query at all:
Lick lick = em.get(Lick.class, 2);
List<Cat> cats = lick.getCats();