JPA CriteriaQuery: getCount + condition - jpa

I try to get all the count of Articles (Article.class) which are not analyzed (analyzed == false).
Sadly the following code returns absolutely wrong numbers.
Would anybody know why?
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Long> query = cb.createQuery(Long.class);
query.select(cb.count(query.from(Article.class)));
Root<Article> articles = query.from(Article.class);
Predicate condition = cb.isFalse(articles.get(Article_.analyzed));
query.where(condition);
TypedQuery<Long> unanalyzedArticlesAmount = entityManager.createQuery(query);
return unanalyzedArticlesAmount.getSingleResult();

finally read this post:
How to count the number of rows of a JPA 2 CriteriaQuery in a generic JPA DAO?
and found the following solution:
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery query = cb.createQuery();
Root<Article> root = query.from(Article.class);
query.select(cb.count(root));
Predicate condition = cb.isFalse(root.get(Article_.analyzed));
query.where(condition);
TypedQuery<Long> unanalyzedArticlesAmount = entityManager.createQuery(query);
return unanalyzedArticlesAmount.getSingleResult();

Related

Dynamic JPA OR Expression

How can I construct Criteria Query to update status of multiple items?
final CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaUpdate<Item> query = builder.createCriteriaUpdate(Item.class);
Root<Item> root = query.from(Item.class);
List<Predicate> predicates = new ArrayList<Predicate>();
for(Long id : itemIds)
{
predicates.add(builder.or(builder.equal(root.get(Item_.id), id)));
}
query.set(root.get(Item_.status), status)
.where(predicates.toArray(new Predicate[predicates.size()]));
entityManager.createQuery(query).executeUpdate();
The above query only work if itemIds. size() == 1. If the itemIds.size() > 2 then the entities will not be updated. Can anyone help to construct correct predicate for OR expression please.
Thank in advance!

JPA CriteriaBuilder - not in a Collection

What is the difference between:
First test run on the Builder:
Predicate predicate = root.get(PersonEntity_.name).in(names);
criteriaBuilder.not(predicate);
Second test run on the Query:
Predicate predicate2 = root.get(PersonEntity_.name).in(names).not();
criteriaQuery.where(predicate2);
This seems to give the same results. Am I missing something? Should we choose the CriteriaBuilder above the CriteriaQuery?
Complete example:
List<String> names = new ArrayList<String>();
names.add("John");
names.add("Emma");
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<PersonEntity> criteriaQuery = criteriaBuilder.createQuery(PersonEntity.class);
Root<PersonEntity> root = criteriaQuery.from(PersonEntity.class);
// First test run on the Builder
Predicate predicate = root.get(PersonEntity_.name).in(names);
criteriaBuilder.not(predicate);
// Second test run the query
// Predicate predicate2 = root.get(PersonEntity_.name).in(names).not();
// criteriaQuery.where(predicate2);
List<PersonEntity> list = entityManager.createQuery(cq).getResultList();
There is not difference between these variants. Both statements result in the same.

Difference between CriteriaBuilder and CriteriaQuery for a Collection

What is the difference between:
criteriaBuilder.in(predicate);
criteriaQuery.where(predicate);
This seems to give the same results. Am I missing something? Should we choose the builder above the query?
Complete example:
List<String> names = new ArrayList<String>();
names.add("John");
names.add("Emma");
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<PersonEntity> criteriaQuery = criteriaBuilder.createQuery(PersonEntity.class);
Root<PersonEntity> root = criteriaQuery.from(PersonEntity.class);
Predicate predicate = root.get(PersonEntity_.name).in(names);
criteriaBuilder.in(predicate);
// or alternative: criteriaQuery.where(predicate);
List<PersonEntity> list = entityManager.createQuery(cq).getResultList();
criteriaBuilder.in(predicate) creates a new predicate. You should file a bug with your provider if it is adding the predicate to the query, as this will not be portable. According to the specification it creates a new predicate, just as root.get(PersonEntity_.name).in(names) does. The query should only use the predicate if it gets added to it such as by calling criteriaQuery.where(predicate).

How to write subquery using criteria builder

Here I am using NativeQuery to perform selecting lookup type using subquery this is working right but I want to use Criteria Builder. How can I use it?
Query query = em.createNativeQuery(
"SELECT * FROM LOOKUPMASTER WHERE PARENTLOOKUPTYPEID = (SELECT LOOKUPID FROM LOOKUPMASTER WHERE LOOKUPTYPE =? ) ",
Lookupmaster.class
);
query.setParameter(1, lookUpType);
I tried to write the above query using criteria builder but I am getting different result here is my criteria query.
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery cq = cb.createQuery(Lookupmaster.class);
Root<Lookupmaster> rt = cq.from(Lookupmaster.class);
Path<Object> path = rt.get("parentlookuptypeid");
cq.select(rt);
Subquery<Lookupmaster> subquery = cq.subquery(Lookupmaster.class);
Root rt1 = subquery.from(Lookupmaster.class);
subquery.select(rt1.get("lookupid"));
subquery.where(cb.equal(rt.get("lookuptype"),lookUpType));
cq.where(cb.in(path).value(subquery));
Query qry =em.createQuery(cq);
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Object> criteriaQuery = criteriaBuilder.createQuery();
Root<EMPLOYEE> from = criteriaQuery.from(EMPLOYEE.class);
Path<Object> path = from.get("compare_field"); // field to map with sub-query
from.fetch("name");
from.fetch("id");
CriteriaQuery<Object> select = criteriaQuery.select(from);
Subquery<PROJECT> subquery = criteriaQuery.subquery(PROJECT.class);
Root fromProject = subquery.from(PROJECT.class);
subquery.select(fromProject.get("requiredColumnName")); // field to map with main-query
subquery.where(criteriaBuilder.equal("name",name_value));
subquery.where(criteriaBuilder.equal("id",id_value));
select.where(criteriaBuilder.in(path).value(subquery));
TypedQuery<Object> typedQuery = entityManager.createQuery(select);
List<Object> resultList = typedQuery.getResultList();
Here is a link
another article

Join Two Tables using JPA on non-id column using Specification

Is it possible to join two tables on non-primary keys of the Entities, using specification? If yes, Can you please let me know how to do that?
The attribute is of basic type -> Long.
Thanks in advance.
Found the answer to the question
Hope it helps someone.
Join<PARENT, CHILD> tableJoin = null;
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<PARENT> criteriaQuery = criteriaBuilder.createQuery(PARENT.class);
Root<PARENT> from = criteriaQuery.from(PARENT.class);
List<Predicate> predicateList = ByEntityCriteriaHelper.getPredicatesByPatternOnAttributes(entityManager, searchObject, from, criteriaQuery, criteriaBuilder);
Predicate[] predicates = new Predicate[predicateList.size()];
tableJoin = from.join("CHILD");
predicateList.add(criteriaBuilder.equal(tableJoin.get("id") , searchObject.getChildObject.getId()));
criteriaQuery.where(predicateList.toArray(predicates));
TypedQuery<PARENT> typedQuery = (TypedQuery<PARENT>)entityManager.createQuery(criteriaQuery);
List<PARENT> resultList = typedQuery.getResultList();