Hibernate sum and group - java

everybody:
So, I have this system created with Hibernate and Spring, and I want to create Reports to see the total piece and the total sold per object, but I'm having troubles to understand how to create this Mysql query to hibernate criteria.
This is my query:
SELECT
SUM(laborderdetail.total) AS suma,
sum(laborderdetail.quantity) AS total,
laborderdetail.`itemMaster_id` AS total,
itemmaster.`ITEMNAME` AS total,
udc.`STRVALUE1` AS total
FROM
`laborderdetail` laborderdetail INNER JOIN `itemmaster` itemmaster ON laborderdetail.`itemMaster_id` = itemmaster.`id`
INNER JOIN `udc` udc ON itemmaster.`linetype_id` = udc.`id`
INNER JOIN `laborderdetail` laborderdetail_A ON itemmaster.`id` = laborderdetail_A.`itemMaster_id`
INNER JOIN `laborder` laborder ON laborderdetail_A.`labOrder_id` = laborder.`id`
INNER JOIN `laborder_laborderdetail` laborder_laborderdetail ON laborderdetail_A.`id` = laborder_laborderdetail.`labOrderDetail_id`
AND laborder.`id` = laborder_laborderdetail.`LABORDER_id`
AND laborderdetail.`id` = laborder_laborderdetail.`labOrderDetail_id`
AND laborder.`id` = laborderdetail.`labOrder_id`
AND udc.`id` = laborder.`rate_id`
AND udc.`id` = laborder.`priceList_id`
AND udc.`id` = laborder.`orderReference_id`
WHERE laborder.`company_id` = 1
GROUP BY
laborderdetail.itemMaster_id
ORDER BY
udc.STRVALUE1 ASC
I know I have to use criteria.setFetchMode to JOIN all my tables and then use ProjectionList for my SUM, but the way the system is programmed makes me confused cause in my model of LabOrder I have this code
#OneToMany(fetch=FetchType.EAGER, cascade=CascadeType.ALL)
private Set<LabOrderDetail> labOrderDetail;
So when I try this code:
DetachedCriteria criteria = DetachedCriteria.forClass(LabOrder.class);
criteria.setFetchMode("laborderdetail", FetchMode.JOIN);
if (this.companyId != 0)
criteria.add(Restrictions.eq("company.id", this.companyId));
ProjectionList projectionList = Projections.projectionList();
projectionList.add(Projections.groupProperty("laborderdetail.itemMaster_id"));
projectionList.add(Projections.sum("laborderdetail.total"));
projectionList.add(Projections.sum("laborderdetail.quantity"));
criteria.setProjection(projectionList);
criteria.addOrder(Order.asc("laborderdetail.itemMaster_id"));
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
List<LabOrder> list = hibernateTemplate.findByCriteria(criteria);
I got this error with my line projectionList.add(Projections.groupProperty("laborderdetail.itemMaster_id"));
This is the error:
could not resolve property: laborderdetail.itemMaster_id of: com.gds.model.LabOrder
I know is cause itemMaster_id is in my model of laborderdetail, but how can I do my query?
Maybe it's silly thing but I don't have any clue since I'm not that familiarize with hibernate.
Thanks.

Related

Why hibernate add to my query cross join at the end

I am constructing and running a query via this Hibernate-based code:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Tuple> criteria = cb.createTupleQuery();
Root<hisaVO> hisa = criteria.from(hisaVO.class);
Root<EstablecVO> establec = criteria.from(EstablecVO.class);
Root<DisaVO> disa = criteria.from(DisaVO.class);
Root<RedVO> red1 = criteria.from(RedVO.class);
Root<MicroredVO> microred = criteria.from(MicroredVO.class);
Root<Unidad_EjecutoraVO> ue1 = criteria.from(Unidad_EjecutoraVO.class);
Join<hisaVO,EstablecVO> j1 = hisa.join("estab");
Join<EstablecVO,DisaVO> j2 = j1.join("disa") ;
Join<EstablecVO,RedVO> j3 = j1.join("red") ;
Join<EstablecVO,MicroredVO> j4 = j1.join("microred") ;
Join<EstablecVO,Unidad_EjecutoraVO> j5 = j1.join("ue") ;
criteria.multiselect(j3.get("red_nombre"), cb.count(hisa))
.groupBy(red1.get("red_nombre"));
return em.createQuery(criteria).getResultList();
The log shows Hibernate is implementing that via this corresponding SQL:
select
redvo3_.red_nombre as col_0_0_,
count(hisavo0_.id) as col_1_0_
from
hisa hisavo0_
inner join establec establecvo6_
on hisavo0_.cod_estab=establecvo6_.COD_ESTAB
inner join disa disavo7_
on establecvo6_.cod_disa=disavo7_.id
inner join red redvo8_
on establecvo6_.cod_red=redvo8_.id
inner join microred microredvo9_
on establecvo6_.cod_mic=microredvo9_.id
inner join unidad_ejecutora unidad_eje10_
on establecvo6_.cod_ue=unidad_eje10_.id
cross join establec establecvo1_
cross join disa disavo2_
cross join red redvo3_
cross join microred microredvo4_
cross join unidad_ejecutora unidad_eje5_
group by redvo3_.red_nombre
It seems to be adding extra, unexpected cross joins at the end of the query. Why is it doing that?
You give your query multiple roots via multiple invocations of CriteriaQuery.from(). Each one after the first is reflected in the final query via a cross join. That's roughly what it means to be a query root.
You do not need to (and should not) use CriteriaQuery.from() to add entities to the query that you mean to be associated via inner joins corresponding to mapped relationships -- those you connect via a Join used as the Selection when you run your query.

QueryDSL - order by count as alias

I'm using queryDSL to get users with some additional data from base:
public List<Tuple> getUsersWithData (final SomeParam someParam) {
QUser user = QUser.user;
QRecord record = QRecord.record;
JPQLQuery = query = new JPAQuery(getEntityManager());
NumberPath<Long> cAlias = Expressions.numberPath(Long.class, "cAlias");
return query.from(user)
.leftJoin(record).on(record.someParam.eq(someParam))
.where(user.active.eq(true))
.groupBy(user)
.orderBy(cAlias.asc())
.list(user, record.countDistinct().as(cAlias));
}
Despite it's working as desired, it generates two COUNT() in SQL:
SELECT
t0.ID
t0.NAME
to.ACTIVE
COUNT(DISTINCT (t1.ID))
FROM USERS t0 LEFT OUTER JOIN t1 ON (t1.SOME_PARAM_ID = ?)
WHERE t0.ACTIVE = true
GROUP BY t0.ID, to.NAME, t0.ACTIVE
ORDER BY COUNT(DISTINCT (t1.ID))
I want to know if it's possible to get something like this:
SELECT
t0.ID
t0.NAME
to.ACTIVE
COUNT(DISTINCT (t1.ID)) as cAlias
FROM USERS t0 LEFT OUTER JOIN t1 ON (t1.SOME_PARAM_ID = ?)
WHERE t0.ACTIVE = true
GROUP BY t0.ID, to.NAME, t0.ACTIVE
ORDER BY cAlias
I failed to understand this from documentation, please, give me some directions if it's possible.
QVehicle qVehicle = QVehicle.vehicle;
NumberPath<Long> aliasQuantity = Expressions.numberPath(Long.class, "quantity");
final List<QuantityByTypeVO> quantityByTypeVO = new JPAQueryFactory(getEntityManager())
.select(Projections.constructor(QuantityByTypeVO.class, qVehicle.tipo, qVehicle.count().as(aliasQuantity)))
.from(qVehicle)
.groupBy(qVehicle.type)
.orderBy(aliasQuantity.desc())
.fetch();
select
vehicleges0_.type as col_0_0_, count(vehicleges0_.pk) as col_1_0_
from vehicle vehicleges0_
group by vehicleges0_.type
order by col_1_0_ desc;
I did something like that, but I did count first before ordering. Look the query and the select generated.
That's a restriction imposed by SQL rather than by queryDSL.
You may try to run your suggested query in a DB console - I think it won't execute, at least not on every DB.
But I don't think this duplicated COUNT() really creates any performance overhead.

Java Hibernate HQL SQL INNER JOIN query not working- Oracle

Hibernate / Java newbie here, any help will be greatly appreciated!
So...... I have a table called ITEMS and a ITEM_OWNER_JOIN table joined by the
"itemKey" column and the "owners" column which is a Set of String values...
In Item.java I have:
#ForeignKey(name="FK_ITEM_OWNER_FK")
#ElementCollection(targetClass=java.lang.String.class, fetch = FetchType.Eager)
#JoinTable(name= "ITEM_OWNER_JOIN", joinColumns=#JoinColumn(name="itemKey"))
private Set<String> owners = new HashSet<String>();
and basically I'm trying to run a HQL querying for results where the owners match a
searchText param....
so I've tried:
Query q = session.createQuery("select distinct i.itemKey from Item i inner join"+
" i.owners o where o.owners like '"+searchText+"'");
and I am getting a org.hibernate.QueryException: cannot dereference scalar collection element: owners [select distinct w.workspaceKey from.....]
I've tried researching for that exception to no avail... :(
Thank you for your time!
Something as below
HQL
select i
from Item i
inner join i.owners io
where io like 'searchText';
Oracle Query
SELECT Distinct(i.itemKey)
FROM Item i, ITEM_OWNER_JOIN io
WHERE i.itemKey = io.itemKey and io.x like '%%';
where 'x' is column name.
Working example from my application
From entity:
#ElementCollection
#JoinTable(name = "rule_tagged_name", joinColumns = #JoinColumn(name = "re_rule", referencedColumnName = "id"))
private List<String> ruleTagNames;
DB Columns
RE_RULE NUMBER
RULE_TAG_NAMES
HQL
Select ru FROM Rule ru inner join ru.ruleTagNames rt_name WHERE rt_name in :tagNameList
Try using with IN operator as owners is multiple.
Query hqlQuery = session.createQuery("select distinct i.itemKey from Item i inner join"+
" i.owners o where o.owners in :ownersParam");
Then set parameter owners with the owner set value,
Set<String> ownerSet = new HashSet<String>();
ownerSet.add(searchText);
hqlQuery.setParameterList("ownersParam", ownerSet);
//then retrieve result

EclipseLink Criteria API count in results after joining table

After ours of searching I was still unable to find a way to write this SQL equivalent in EclipseLink criteria query:
SELECT preke.*, count(nuotrauka.prid) AS cnt FROM preke LEFT JOIN nuotrauka ON nuotrauka.prid=preke.prid WHERE trash = 1 GROUP BY preke.prid ORDER BY cnt DESC
I tried joins, multiselects and etc. I need getResultList() to return me List within List like list[0] - (Preke)preke1, list[1] - (Integer)count1; list[0] - (Preke)preke2, list[1] - (Integer)count2 ... .
EDIT 1:
CriteriaBuilder cb = EntityManager.getInstance().getCriteriaBuilder();
CriteriaQuery criteriaQuery = cb.createQuery(Tuple.class);
Root<Preke> from = criteriaQuery.from(Preke.class);
Expression<Long> count = cb.count(from.get("images"));
criteriaQuery.where(cb.equal(from.get("trash"), true));
criteriaQuery.multiselect(from.alias("preke"), count.alias("count"));
criteriaQuery.groupBy(from.get("prid"));
TypedQuery<Tuple> typedQuery = EntityManager.getInstance().createQuery(criteriaQuery);
typedQuery.setFirstResult(PAGE * ITEMS_PER_PAGE);
typedQuery.setMaxResults(ITEMS_PER_PAGE);
prekes = typedQuery.getResultList();
...
for(Tuple t : prekes) {
Preke p = (Preke)t.get("preke");
long count = (long)t.get("count");
...
}
It give me following JPQL statement:
SELECT t0.prid AS a1,
...,
COUNT(t1.id)
FROM preke t0,
nuotrauka t1
WHERE
((t0.trash = ?) AND (t1.prid = t0.prid))
GROUP BY t0.prid LIMIT ?, ?
This is almost fine, but it doesn't include results where count is 0.
As above JPQL statement says - t1.prid = t0.prid should be the bad part, how to replace it? I think what I need here is a LEFT JOIN. But how to do it?
Instead of using
Expression<Long> count = cb.count(from.get("images"));
try using
Join<Preke, Nuotrauka> images = from.join("images", JoinType.LEFT);
Expression<Long> count = cb.count(images);

Hibernate detached queries as a part of the criteria query

java experts can you please help me write detached queries as a part of the criteria query for the following SQL statement.
select A.*
FROM AETABLE A
where not exists
(
select entryid
FROM AETABLE B
where B.classpk = A.classpk
and B.userid = A.userid
and B.modifiedDate > A.modifiedDate
)
and userid = 10146
You need to write a correlated subquery. Assuming property / class names match column / table names above:
DetachedCriteria subquery = DetachedCriteria.forClass(AETable.class, "b")
.add(Property.forName("b.classpk").eqProperty("a.classpk"))
.add(Property.forName("b.userid").eqProperty("a.userid"))
.add(Property.forName("b.modifiedDate").gtProperty("a.modifiedDate"));
Criteria criteria = session.createCriteria(AETable.class, "a")
.add(Property.forName("userid").eq(new Integer(10146)))
.add(Subqueries.notExists(subquery);
Just one addition to the above query. If the entryid is not the primary key, then you'll need to add projection.
DetachedCriteria subquery = DetachedCriteria.forClass(AETable.class, "b")
.add(Property.forName("b.classpk").eqProperty("a.classpk"))
.add(Property.forName("b.userid").eqProperty("a.userid"))
.add(Property.forName("b.modifiedDate").gtProperty("a.modifiedDate"))
.add(setProjection(Projections.property("entryId")); // Additional projection property
Criteria criteria = session.createCriteria(AETable.class, "a")
.add(Property.forName("userid").eq(new Integer(10146)))
.add(Subqueries.notExists(subquery);

Categories