JPA criteria: count from multiselect query - jpa

I want to implement a table component with pagination. The result in the table is retrieved by a multiselect-query like this:
SELECT DISTINCT t0.userId,
t0.userName,
t1.rolleName
FROM userTable t0
LEFT OUTER JOIN roleTable t1 ON t0.userId = t1.fkUser
WHERE(t0.userType = 'normalUser' AND t1.roleType = 'loginRole')
This result I can get via a multiselect-query.
Now for the pagination I have to retrieve the total rowcount at first.
Is there anybody who can define a criteriaquery for one of this sql? I failed because a subquery does not support multiselects and I do not know how to get this distinct into a count statement.
SELECT COUNT(*) FROM
(
SELECT DISTINCT t0.userId,
t0.userName,
t1.rolleName
FROM userTable t0
LEFT OUTER JOIN roleTable t1 ON t0.userId = t1.fkUser
WHERE(t0.userType = 'normalUser' AND t1.roleType = 'loginRole')
)
or
SELECT COUNT(DISTINCT t0.userId || t0.userName || t1.rolleName)
FROM userTable t0
LEFT OUTER JOIN roleTable t1 ON t0.userId = t1.fkUser
WHERE(t0.userType = 'normalUser' AND t1.roleType = 'loginRole')
Thanks in advance!
Btw. I am using OpenJpa on a WebSphere AppServer

The following is not tested but should work:
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Long> query = builder.createQuery(Long.class);
Root<User> t0 = query.from(User.class);
Join<User, Role> t1 = t0.join("roles", JoinType.LEFT);
query.select(builder.concat(t0.get(User_.userId), builder.concat(t0.get(User_.userName), t1.get(Role_.rolleName))).distinct(true);
query.where(cb.equal(t0.get("userType"), "normalUser"), cb.equal(t1.get("roleType"), "loginRole"));
TypedQuery<Long> tq = em.createQuery(query);

Due to known issue https://jira.spring.io/browse/DATAJPA-1532 Multiselect does not work with repo.findall method. I handled this by autowiring entity manager to service class.
#Autowired
EntityManager entityManager;
public List<?> getResults() throws ParseException
{
//ModelSpecification modelSpecification = new ModelSpecification();
CriteriaQuery<DAO> query = modelSpecification.getSpecQuery();
TypedQuery<DAO> typedQuery = entityManager.createQuery(query);
List<?> resultList = typedQuery.getResultList();
//List<DAO> allData = entityManager.createQuery(query).getResultList();
return resultList;
}
You can find working code here https://github.com/bsridharpatnaik/CriteriaMultiselectGroupBy

Related

#Query annotation not working in JPA Repository

#Query(value = "SELECT * FROM MEMBER m " +
"LEFT JOIN COMPANY_TYPE c ON c.TYPE_CODE = m.TYPE_CODE " +
"LEFT JOIN COMPANY_LOCATION l on l.LOCATION_CODE = m.LOCATION_CODE " +
"WHERE l.LOCATION_CODE = :location AND c.TYPE_CODE = :type", nativeQuery = true)
List<Member> findByOption(#Param("type")Long companyType, #Param("location")Long companyLocation);
This is the method I'm trying to use in MemberRepository interface that extends JPARepository<Member, Long>.
#ManyToOne
#JoinColumn(name = "TYPE_CODE")
private CompanyType company_Type;
#ManyToOne
#JoinColumn(name = "LOCATION_CODE")
private CompanyLocation company_Location;
And this is part of entity class Member.
I am trying to get filtered list of members according to the company type and location code(id). However, the slice test results always return all of members.
I want to know if there are other settings that needs to be set in order for the #Query annotation to work, and if the native query I put in the annotation is wrong.
Any other ideas of how to get filtered results in Spring Data JPA is also welcomed.
This is a very subtle mistake, but rather than using SELECT * you should be using SELECT m.*:
Query(value = "SELECT m.* FROM MEMBER m " +
"LEFT JOIN COMPANY_TYPE c ON c.TYPE_CODE = m.TYPE_CODE " +
"LEFT JOIN COMPANY_LOCATION l on l.LOCATION_CODE = m.LOCATION_CODE " +
"WHERE l.LOCATION_CODE = :location AND c.TYPE_CODE = :type", nativeQuery = true)
List<Member> findByOption(#Param("type")Long companyType, #Param("location")Long companyLocation);
The reason for this is that SELECT m.* returns only the columns from the Member entity/table. SELECT * instructs JPA to return columns from all tables in the query. You would need a method return signature of List<Object[]> in that case.

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.

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

EF 4.0 LINQ one to many / many to one

Just starting to use LINQ as well as EF.
I have a set of tables in the following configuration:
PublicUtility (UtilityCode) * ----> 1 (UtilityCode) Utility (UtilityCode) 1 -----> * (UtilityCode) UtilityDetail
I have a query in SQL. Based on some other business rules this query will either return 1 value or NULL.
SELECT
#UtilityCode = UtilityDetail.UtilityCode
FROM
UtilityDetail
INNER JOIN PublicUtility ON
PublicUtility.SubdivisionCode = #SubdivisionCode AND
PublicUtility.Year = #PublicUtilityYear AND
PublicUtility.UtilityCode = UtilityDetail.UtilityCode
WHERE
UtilityDetail.DebtPurposeCode = #DebtPurposeCode
How could I rewrite this using LINQ to entities?
using (YourObjectContext ctx = new YourObjectContext())
{
var code = (from ud in ctx.UtilityDetails
join pu in PublicUtility on ud.UtilityCode equals pu.UtilityCode
where ud.DeptPurposeCode == [code_value] && pu.SubdivisionCode == [subdivcode_value] && pu.Year == [year_value]
select new {ud.UtilityCode}).FirstOrDefault();
}

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