How to select distinct table from joined tables with Hibernate Criteria API? - java

I'm trying to implement a query like this:
SELECT DISTINCT C.* FROM A
join B on A.some_id = B.some_id
join C on B.some_id = C.some_id;
With Hibernate Criteria API.
I need to have distinct results for whole C table, not just for some column(s) of it.
I tried to do like that:
Criteria criteria = createCriteria(C.class, "ct")
.createCriteria("B", "bt")
.createCriteria("A", "at")
.//Some restrictions which are applied to all tables
And like that:
Criteria criteria = createCriteria(A.class, "at")
.createCriteria("B", "bt")
.createCriteria("C", "ct")
.//Some restrictions which are applied to all tables
(I don't see a difference though).
Tried to ad ResultTransformer:
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
Tried to put all colums into ProjectionsList and then:
criteria.setProjection(Projections.distinct(projectionList));
But that projection only adds "distinct" keyword to first column in list but not to whole table.
What I want to achieve - is something like that:
criteria.setProjection(Projections.distinct("C.*"));
but I only can add a column here, can't use wildcards like in query.
Any help is greatly appreciated.

You should select columns from table 'C' not from table 'A' like below.
SELECT distinct (*) FROM C
it can be written in hibernate criteria as follows:
Criteria criteria = session.createCriteria(C.class);
criteria = criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
ResultTransformer rt = new DistinctRootEntityResultTransformer();
List list = rt.transformList(criteria.list());

Related

How to use Count(*) in JPQL

I have a JPQL subquery in which I want to return a list of customerIds that meet a specific condition based on a ManyToOne relationship as shown below:
SELECT c.customerId
FROM Customer c
INNER JOIN FETCH c.customersChild cc
LEFT JOIN FETCH c.childsPet cp on cp.name = 'Rover'
GROUP BY c.customerId
HAVING (COUNT(cp.name) / COUNT(*)) = 1
In this case, the customer should only be present in the list if all of their childrens' pet's names are Rover. The HAVING (COUNT(cp.name) / COUNT(*)) = 1 clause works as-is in Oracle (SQL), since COUNT(cp.name) counts the number of non-null rows for each customer, and COUNT(*) counts the total number of rows (including nulls present due to the left join) for each customer... I believe COUNT(cp.name) works in JPQL but it doesn't seem like there is equivalent for COUNT(*)... does anyone know if there is a way to count all the rows within a group including nulls?
I would suggest you rewrite your query to the more understandable anti-join variant:
SELECT c.customerId
FROM Customer c
WHERE NOT EXISTS (
SELECT 1
FROM c.customersChild cc
JOIN cc.childsPet cp
WHERE cp.name = 'Rover'
)

Hibernate Criteria filter Entity where ManyToMany relation contains multiple objects

I need help with Hibernate Criteria API.
I have a class Job that contain a list of Skill in ManyToMany relationship.
I need to select jobs based on a skill list given as parameter.
I've tried with Restriction.in("skill.id",ids) but this gives me wrong list.If i've selected 2 skills in search form i want the jobs that contain BOTH of them,so i need somehow to implement AND clause.
I've tried with Conjunction:
Conjunction and = Restrictions.conjunction();
for(Skill skill:job.getSkills()){
and.add(Restrictions.eq("skill.id",skill.getId()));
}
And this:
Criteria crit = criteria.createCriteria("skills",JoinType.LEFT_OUTER_JOIN);
for(Skill skill:job.getSkills()){
crit.add(Restrictions.eq("id", skill.getId()));
}
but it creates same alias for skill and it gives me no result.
sql is and (skill1_.ID=? and skill1_.ID=?)
Can anyone help me with this ?thanks
UPDATE:
HQL Query will be like:
select a from Job a where exists (select skill1.id from Skill skill1 join skill1.jobs r where r.id=a.id and skill1.id=1) and exists (select skill2.id from Skill skill2 join skill2.jobs r where r.id=a.id and skill2.id=4)
I need Criteria based on this.
for(Skill skill:job.getSkills()){
DetachedCriteria subquery = DetachedCriteria.forClass(Skill.class,"skill");
subquery.add(Restrictions.eq("id",skill.getId()));
subquery.setProjection(Projections.property("id"));
subquery.createAlias("jobs", "job");
subquery.add(Restrictions.eqProperty("job.id", "Job.id"));
criteria.add(Subqueries.exists(subquery));
}
I managed to solve it.now it works perfect.

Automatic generation of java hibernate code from sql code

Is there a tool able to generate java hibernate code starting from the sql query?
(like reverse of what hibernate does, generating selects from java code) It will help me move all my queries to hibernate!
I mean if i have a select with parameters like this:
select ta.id label, ta.nume value
from ar
left outer join ta ta on idp = ta.ID
where ta.status = 1
and (dp = 0 OR ps = idps_)
and status = 1
order by ta.nume;
to obtain in the end something like this:
DetachedCriteria criteria = DetachedCriteria.forEntityName("ar");
criteria.createAlias("ta", "ta", Criteria.LEFT_JOIN);
criteria.add(Restrictions.eq("ta.status", 1));
Criterion eq = Restrictions.eq("ps.id", idps_);
Criterion isZero = Restrictions.eq("dp.id", 0);
Criterion or = Restrictions.or(eq, isZero);
criteria.add(or);
criteria.add(Restrictions.eq("status", 1));
ProjectionList projectionList = Projections.projectionList();
projectionList.add(Projections.property("ta.id"), "value");
projectionList.add(Projections.property("ta.nume"), "label");
criteria.setProjection(Projections.distinct(projectionList));
criteria.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
criteria.addOrder(Order.asc("ta.nume"));
OR something similar using maps as output...
providing to the tool the path where i store the mappings of the entities/beans with the tables (or the path to the beans, if the beans are annotated)
You have the HQL that is an SQL-like dialect to work with Hibernate. You use field names from entities instead of those from tables. It supports joins etc.
In fact, Criteria API has very limited support of joins (at least it was so last time I've tried to used) and I've a few times finished rewriting everything from Criteria API to HQL, so I now simply tread Criteria API as no option.
In HQL you can also use SQL functions, both in SELECT and in WHERE part, those embedded and those you've written yourself.

How to map native query to one model class?

Hi I´m using Eclipselink and I did a native query to select some fields of 2 tables. I mapped my table Logins in a model class. I would not like to map my table "B" because I need only 2 fields of this table on my sql result.. can I map this 2 fields in my Logins table to my sql result ?
My sql is this:
select l.login_id, s.lugarcerto,s.vrum, l.username, l.first_name, l.last_name, l.phone, l.fax_number, l.address, l.zip,
l.address2 as 'birth_date', l.city as 'cpf_cnpj'
from Logins l
join (select se.login_id, lugarcerto = min(case when se.service = 'IM' then '1' end), vrum = min(case when se.service = 'VE' then '1' end)
from (select distinct ad.login_id, substring(ap.Rate_code,(CHARINDEX('-', ap.Rate_code)+1),2) as 'service'
from Ad_Data.dbo.ad ad
join Ad_Data.dbo.ad_pub ap on (ad.ad_id = ap.ad_id)
where ap.ad_type =1) se
group by se.login_id) s on (s.login_id = l.login_id)
I did map Logins table and I want to map s.lugarcerto and s.vrum to my SQL query result.
There´s anyway to just add it to my Logins model ?
Not without having mappings for the attributes you want those values put into, and not without causing problems with them being cached in the entity.
Why not just return the values beside the entity, much like you would with a JPQL query such as: "Select l, subquery1, subquery2 from Logins l" ie:
Query q = em.createNativeQuery(yourQueryString, "resultMappingName");
And in the entity, include the annotation:
#SqlResultSetMapping(name="resultMappingName",
entities={#EntityResult(entityClass=com.acme.Logins.class, )},
columns={#ColumnResult(name="LUGARCERTO"), #ColumnResult(name="VRUM")}
)
Best Regards,
Chris

How use hibernate criteria for a left outer join without direct link into the two tables

I'm trying to translate a SQL quest into Hibernate criteria.
My quest is working in SQL :
select * from objective
left outer join conditionstate
on objective.conditionid = conditionstate.conditionid
and conditionstate.personid = XXXX
where objective.toto_id = YYYYY
The objective is not directly mapped to the condition_state, but into a condition.
objective --> condition <-- condition_state
I've tested something like :
final DetachedCriteria criteriaObjective =
DetachedCriteria.forClass(Objective.class);
criteriaObjective.createAlias("conditionState", "conditionState", Criteria.LEFT_JOIN);
without success..
It's hard to suggest something without seeing your actual mappings. Going by your explanation and assuming that both condition and conditionState are mapped as many-to-one, you'd write something like:
final DetachedCriteria criteriaObjective =
DetachedCriteria.forClass(Objective.class);
criteriaObjective
.createCriteria("condition", Criteria.LEFT_JOIN)
.createCriteria("conditionState", Criteria.LEFT_JOIN)
.add(Restrictions.eq("personid", "XXXX") );
criteriaObjective.add(Restrictions.eqProperty("toto_id", "YYYY") );
Note that the above is NOT equivalent to the SQL query you've provided because "personid" condition will be generated as part of "WHERE" clause. As far as I know it's impossible to do a left join with condition using Criteria API - you may need to use HQL instead which provides with keyword for that exact purpose:
select o from objective as o
left join o.condition as c
left join c.conditionState as cs
with cs.person_id = 'XXXX'
and o.toto_id = 'YYYY'

Categories

Resources