Criteria count + sub query - jpa

I am trying to implement something like:
Select thread from Thread where(Select Sum(thread.emails) from Thread)
is equals to ?
How could I implement it with Criteria + JPA?

There is a size() method in CriteriaBuilder to define size of a collection.
CriteriaBuilder cb = em.getCriteriaBuilder(); //em is EntityManager
CriteriaQuery<Thread> cq = cb.createQuery(Thread.class);
Root<Thread> root = cq.from(Thread.class);
Expression<Collection<String>> emails = root.get("emails");
cq.where(cb.equal(cb.size(emails), PARAM));

Related

Count Criteria joining columns

I'm trying to count the rows of the filter the user uses, when the user wants to list all it works fine, the problem is when they use filters and that makes some joins to work properly.
(This is used for a lazy datatable in jsf)
My criteria code is:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<CarreraHorizontal> cq = cb.createQuery(CarreraHorizontal.class);
Root<CarreraHorizontal> root = cq.from(CarreraHorizontal.class);
CriteriaQuery<Long> cqCount = cb.createQuery(Long.class);
List<Predicate> predicates = new ArrayList<Predicate>();
Join<CarreraHorizontal, Gdp> childJoin = root.join("gdp", JoinType.LEFT);
Join<CarreraHorizontal, Empleado> childJoin2 = root.join("empleado", JoinType.LEFT);
if (!StringUtils.isBlank(grupoTitulacion))
predicates.add(cb.like(root.<String>get("grupoTitulacion"), "%" + grupoTitulacion + "%"));
if(gdp0Bool) {
predicates.add(cb.like(childJoin.<String>get("nombre"), "GDP0"));
if(!StringUtils.isBlank(gdp0Combo))
predicates.add(cb.le(childJoin.<Integer>get("numEscalones"), Integer.parseInt(gdp0Combo)));
}
if(epg6) {
predicates.add(cb.equal(childJoin2.get("progresionEscalon"), epg6));
}
//cq.where(cb.and(predicates.toArray(new Predicate[predicates.size()])));
cqCount.where(cb.and(predicates.toArray(new Predicate[predicates.size()])));
Root<CarreraHorizontal> rootCount = cqCount.from(CarreraHorizontal.class);
CriteriaQuery<Long> a = cqCount.select(cb.count(rootCount));
TypedQuery<Long> res = em.createQuery(a.select(cb.count(rootCount)));
return res.getSingleResult();
My exception is:
Invalid path: 'generatedAlias1.progresionEscalon' [select count(generatedAlias0) from es.valencia.gp.sbch.entity.CarreraHorizontal as generatedAlias0 where generatedAlias1.progresionEscalon=:param0]
I tried everything I found but it's still not working.

Criteria Builder Convert Lower different variant

Everywhere I look I see people using this
predicate =
criteriaBuilder.like(criteriaBuilder.lower(root.get(Product_.prodName)),
wrapper.getProdName());
especially I mean this Product_.prodName. I have no idea what it is, what it does and why I can't use or have it in my context. Here my code which not works:
Look at the line with !nachname.isEmpty
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Telefonbuch> query = builder.createQuery(Telefonbuch.class);
Root<Telefonbuch> root = query.from(Telefonbuch.class);
EntityType<Telefonbuch> model = em.getMetamodel().entity(Telefonbuch.class);
List<Predicate> predicates = new ArrayList<Predicate>();
if (!vorname.isEmpty()) {
Predicate condition = builder.like(root.<String>get("vorname"),"%"+vorname+"%");
predicates.add(condition);
}
if (!nachname.isEmpty()) {
Predicate condition = builder.like(builder.lower(root.get("nachname"),"%"+nachname+"%"));
predicates.add(condition);
}
query.select(root).where(predicates.toArray(new Predicate[predicates.size()]));
eintraege = em.createQuery(query).getResultList();

jpa criteria builder combine pagination and count results

implementing pagination you can use criteria builder to return a page out of a result-set. However, if you need to get the full number of results (pages) you have to run a separate query with the same criteria for the count.
is there a way to combine the two together into single database call and save on performance without returning the full set and implement the page yourself?
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<EntityJpa> cq = cb.createQuery(EntityJpa.class);
Root<EntityJpa> root = cq.from(EntityJpa.class);
Predicate p = cb.conjunction();
cq.where(p);
TypedQuery<EntityJpa> tq = em.createQuery(cq);
return tq.getResultList();
AND the count
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Long> cq = cb.createQuery(Long.class);
Root<EntityJpa> r = cq.from(EntityJpa.class);
Predicate p = cb.conjunction();
cq.where(p);
cq.select(cb.count(r));
TypedQuery<Long> tq = em.createQuery(cq);
return tq.getSingleResult().intValue();
CriteriaQuery<Long> cq = cb.createQuery(Long.class);
cq.select(cb.count(root)).where(pred).distinct(true);
Long maxPages = em.createQuery(cq).getSingleResult();
We Utilize something like this. I am working on a way to cache the results so I don't have to run the count every time it is paged, but this is working for us right now.

How to count the results from a Custom Entity using JPA CriteriaQuery

I am using JPA2.1 criteria API where in I have created a result object using criteria builder construct.
Consider the below sample piece of code.
CriteriaBuilder cb;//Assume cb is obtained here
CriteriaQuery<Report> cq = cb.createQuery(Report.class);// custom selective Class
Root<Student> root = cq.from(Student.class);
Join<Student, XTable> join1 = root.join("xtable", JoinType.INNER);
Join<Student, YTable> join1 = root.join("ytable", JoinType.INNER);
Below is the main line where I would select.
cq.select(cb.construct(Report.class,
root.get("name"), join1.get("address_type"), join2.get("country")));
Now, I would like to do a count on this construct Report.
I tried count like this.
cq.select(cb.count(cb.construct(......)));
// Failed because count accepts Expression and I tried assigning the cb.construct to Expression which is not working.
How to get the count?
I think it would look something like this:
Your code:
CriteriaBuilder cb;//Assume cb is obtained here
CriteriaQuery<Report> cq = cb.createQuery(Report.class);// custom selective Class
Root<Student> root = cq.from(Student.class);
Join<Student, XTable> join1 = root.join("xtable", JoinType.INNER);
Join<Student, YTable> join1 = root.join("ytable", JoinType.INNER);
countItemsByCriteria(entityManagerReference, cq, cb);
private <T> Long countItemsByCriteria(EntityManager em, CriteriaQuery<T> cqEntity, CriteriaBuilder cb) {
CriteriaBuilder builder = cb;
CriteriaQuery<Long> cqCount = builder.createQuery(Long.class);
Root<?> entityRoot = cqCount.from(cqEntity.getResultType());
cqCount.select(builder.count(entityRoot));
cqCount.where(cqEntity.getRestriction());
return em.createQuery(cqCount).getSingleResult();
}
As also described in this post: JPA + Hibernate count(*) using CriteriaBuilder - with generatedAlias

CollectionAttribute testing in JPA CriteriaBuilder

I have a CriteriaBuilder and am trying to create a predicate to restrict results in a CollectionAttribute. I would like to say something like get all entities in this collection where the entity's attribute A equals x. For example, I have lots of People entities. They have a collection of job titles (previous and current) and I'd like to know about all people who have had a title of "banker". Here is an example:
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Object> query = builder.createQuery();
Root<MheAreaLocation> root = query.from(MheAreaLocation.class);
Predicate p2 = builder.equal(root.get(Jobs_.jobs).get(Jobs_.titles), "banker");
TypedQuery<Object> q = em.createQuery(query);
List<Object> resultList = q.getResultList();
...
Any help would be great. I'm struggling to find much about CollectionAttribute and using them in predicates...and I keep getting nulls when I use the join below in the predicate :-( Thanks
This is my actual code:
CriteriaBuilder builder = em.getCriteriaBuilder();
// CriteriaQuery<Tuple> query = builder.createQuery();
CriteriaQuery<Object> query = builder.createQuery();
Root<MheAreaLocation> mheAreaLocationRoot = query.from(MheAreaLocation.class);
CollectionJoin<MheLocation, AtlasLocationGroupMap> join = mheAreaLocationRoot.join(MheAreaLocation_.childLocation).join(MheLocation_.atlasLocationGroupMapCollection);
// .join(AtlasLocationGroupMap_.atlasLocationGroup, JoinType.INNER);
Predicate p1 = builder.equal(mheAreaLocationRoot.get(MheAreaLocation_.parentLocation).get(MheLocation_.mheLocId), "AZP1B");
// Predicate p2 = builder.equal(mheAreaLocationRoot.get(MheAreaLocation_.childLocation).get(MheLocation_.atlasLocationGroupMapCollection).);
Predicate p2 = builder.equal(join.get(AtlasLocationGroupMap_.atlasLocationGroup).get(AtlasLocationGroup_.locationGroupType), "NEXT_STATION");
// query.where(builder.and(e1, e2));
// mheAreaLocationRoot.fetch(MheAreaLocation_.childLocation);
// join.fetch(MheLocation_.atlasLocationGroupMapCollection);
// query.multiselect(mheAreaLocationRoot.get(MheAreaLocation_.parentLocation),
// mheAreaLocationRoot.get(MheAreaLocation_.childLocation));
// query.select(builder.tuple(join.get(AtlasLocationGroupMap_.mheLocation)));
TypedQuery<Object> q = em.createQuery(query);
List<Object> resultList = q.getResultList();
...
Other classes (I can add more if needed):
#StaticMetamodel(MheLocation.class)
public class MheLocation_ {
public static volatile CollectionAttribute<MheLocation, AtlasLocationGroupMap> atlasLocationGroupMapCollection;
public static volatile SingularAttribute<MheLocation, String> mheLocId;
}
Take this example which has classes of Farm and Animal (Farm has a collection<Animal>) and we want to impose a criteria on the name of the Animal. Not exactly the same as yours I think, but may point you in the right direction
CriteriaBuilder qb = emf.getCriteriaBuilder();
CriteriaQuery<Farm> crit = qb.createQuery(Farm.class);
Root<Farm> candidate = crit.from(Farm.class);
candidate.alias("f");
crit.select(candidate);
Metamodel model = emf.getMetamodel();
ManagedType farmType = model.managedType(Farm.class);
Attribute animalAttr = farmType.getAttribute("animals");
Join animalJoin = candidate.join((ListAttribute)animalAttr);
animalJoin.alias("a");
Path nameField = animalJoin.get("name");
Predicate nameEquals = qb.equal(nameField, "Woolly Sheep");
crit.where(nameEquals);
Equates to
SELECT f FROM org.jpox.samples.annotations.one_many.bidir.Farm f JOIN f.animals a WHERE (a.name = 'Woolly Sheep')
HTH