i have a problem when retrieving count from criteria that impact my pagination.
i have this associations that work fine just the count of my result which is wrong for example i have 20 users in my DB but i got 60.
DetachedCriteria criteria = DetachedCriteria.forClass(User.class, "user");
criteria.createAlias("profile", "prof", Criteria.LEFT_JOIN);
criteria.createAlias("userAgencyRole", "adminAgency", Criteria.LEFT_JOIN);
criteria.createAlias("userAgencyRole.agency", "agency",Criteria.LEFT_JOIN);
criteria.createAlias("userAgencyRole.role", "role",Criteria.LEFT_JOIN);
result.setTotalRecords(userDalService.getCountFromCriteria(criteria));
For used projections i have :
ProjectionList projList = Projections.projectionList();
projList.add(Projections.property("name"), "name");
projList.add(Projections.property("email"), "email");
projList.add(Projections.property("userId"), "userId");
projList.add(Projections.property("profile"), "profile");
Any suggestions for this issue
You have to be careful while using Criteria API since joining a one-to-many relationship will not return distinct results by default.
This is a known problem and there are a few ways to prevent it. Some of them are discussed here.
Problem solved by invoking criteria alias if needed based on parameters received from my API. so the result wont be impacted by associations.
Related
This is my first post ever, I usually find the answers im looking for here, but this time i'm stumped.
Below are two sql queries - by first getting the values and then doing a "sum" on the results almost halves the duration, but replicating this with Hibernate Criteria is not that straight forward.
From related posts ive found it looks like the answer will more than likely be some DetachedCriteria function, but I cant find any examples where its been used with "sum".
SELECT (COUNT(DISTINCT(account))) FROM history;
duration 6363ms
SELECT COUNT(*) FROM (SELECT DISTINCT account);
duration 3624ms
My Hibernate criteria for the first query:
Session session = sessionFactory.openSession();
ProjectionList proj = Projections.projectionList()
.add(Projections.countDistinct("account"));
Criteria crit = session.createCriteria(History.class)
.setProjection(proj);
System.out.println(crit.list());
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.
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.
I think this is a very simple question. but unfortunately I cannot find a solution.
I have a mysql database table called "Invoice" having "inv_No","inv_netvalue","inv_date" inv_No is the primary key. I want to get a Invoice object according to a given inv_No. I used a critaria. But this result nothing. list.size() is 0.
Invoice invoice = new Invoice();
invoice.setInvNo(Integer.parseInt(invoiceNo));
Session session = HSession.getSession();
Criteria crit = session.createCriteria(Invoice.class);
crit.add(Example.create(invoice));
List list=crit.list();
but when I used this "FROM Invoice invoice WHERE invoice.invNo='" + invoiceNo + "'" it returns which I expected.
Any one help me please.Let me know where I am wrong..
It's not clear to me why you've got the second createCriteria call. Have you tried this?
Criteria crit = session.createCriteria(Invoice.class);
crit.add(Example.create(invoice));
That follows some of the examples in the docs, for example.
EDIT: Another option is not to use "query by example" but just:
Criteria crit = session.createCriteria(Invoice.class);
crit.add.(Restrictions.eq("invNo", Integer.parseInt(invoiceNo)));
Criteria criteria = session.createCriteria(Invoice.class);
criteria.add.(Restrictions.eq("invNo", Integer.parseInt(invoiceNo)));
is the best way to get the results.
Using Hibernate's Criteria API, I want to select the record within a table with the maximum value for a given column.
I tried to use Projections, creating an alias for max(colunName), then using it in restrictions.eq(), but it keeps telling me "invalid number".
What's the correct way to do that with Hibernate?
You can use a DetachedCriteria to express a subquery, something like this:
DetachedCriteria maxId = DetachedCriteria.forClass(Foo.class)
.setProjection( Projections.max("id") );
session.createCriteria(Foo.class)
.add( Property.forName("id").eq(maxId) )
.list();
References
Hibernate Core Reference Guide
15.8. Detached queries and subqueries
I found that using addOrder and setMaxResults together worked for me.
Criteria c = session.createCriteria(Thingy.class);
c.addOrder(Order.desc("id"));
c.setMaxResults(1);
return (Thingy)c.uniqueResult();
Using the MySQL dialect, this generates a SQL prepared statement about like this (snipping out some of the fields):
select this_.id ... from Thingy this_ order by this_.id desc limit ?
I am not sure if this solution would be effective for dialects other than MySQL.
Use
addOrder(Order.desc("id"))
and fetch just the first result :)
HQL:
from Person where person.id = (select max(id) from Person)
Untested. Your database needs to understand subselects in the where clause.
Too lazy to find out if/how such a subselect can be expressed with the criteria api. Of course, you could do two queries: First fetch the max id, then the entity with that id.
The cleaner solution would also be :
DetachedCriteria criteria = DetachedCriteria.forClass(Foo.class).setProjection(Projections.max("id"));
Foo fooObj =(Foo) criteria.getExecutableCriteria(getCurrentSession()).list().get(0);
Date maxDateFromDB = null;
Session session = (Session) entityManager.getDelegate();
//Register is and Entity and assume maxDateFromDB is a column.
//Status is another entity with Enum Applied.
//Code is the Parameter for One to One Relation between Register and Profile entity.
Criteria criteria = session.createCriteria(Register.class).setProjection(Projections.max("maxDateFromDB") )
.add(Restrictions.eq("status.id", Status.Name.APPLIED.instance().getId()));
if(code != null && code > 0) {
criteria.add(Restrictions.eq("profile.id", code));
}
List<Date> list = criteria.list();
if(!CollectionUtils.isEmpty(list)){
maxDateFromDB = list.get(0);
}
To do it entirely with Detached Criteria (because I like to construct the detached criteria without a session)
DetachedCriteria maxQuery = DetachedCriteria.forClass(Foo.class)
.setProjection( Projections.max("id") );
DetachedCriteria recordQuery = DetachedCriteria.forClass(Foo.class)
.add(Property.forName("id").eq(maxId) );
For the max() function in hibernate:
criteria.setProjection(Projections.max("e.encounterId"));