I have two tables:
Client (clientId, firstName, lastName, gender)
Event (clientId, eventId)
I need to represent a query similar to the following using Criteria:
SELECT c.clientId, c.firstName, c.lastName, c.gender, MAX(eventId)
FROM Client c JOIN Event e ON c.clientId = e.clientId
GROUP BY c.clientId, c.firstName, c.lastName, c.gender
I have tried this:
final Criteria criteria = session.createCriteria(Client.class);
criteria.setFetchMode("Event", FetchMode.JOIN);
criteria.setProjection(Projections.projectionList().add(Projections.groupProperty("clientId")).add(Projections.max("eventId")));
but it throws an exception on the last line with the message:
HibernateQueryException: could not resolve property: eventId of:
Client
How can I specify the join between the Client table which itself contains no column related to the Event table but the clientId column on the Event table is a foreign key back into the Client table?
As you can see, it's really driven off the Client table and that I only need to select the maximum eventId from the Event table. Also, as I mentioned, I am trying to make a change to an existing Criteria query which is based on the Client class. It is used to retrieve all the columns for all active clients. I just need to add one extra column to the query results - the maximum eventId.
Use alias
Criteria criteria = session.createCriteria(Event.class, "et").
createAlias("et.Client", "ct").
setProjection(Projections.projectionList().
add(Projections.groupProperty("et.clientId")).
add(Projections.max("et.eventId")));
For more details on criteria, refer Criteria Queries
That is obvious. Because Client class does not have eventId property, and your criteria is defined for Client class.
When trying to use a property of B class inside a Criteria for A, you have to use Aliases.
All you have to do is to modify your code like this:
final Criteria criteria = session.createCriteria(Event.class, "event");
criteria.createAlias("event.client", "client");
criteria.setProjection(Projections.projectionList().add(Projections.groupProperty("clientId")).add(Projections.max("eventId")));
UPDATED (based on your comment)
As your query needs Event class, you have to have a Criteria for this class. So you have to something like this:
final Criteria criteria = session.createCriteria(Event.class, "event");
criteria.createAlias("event.client", "client");
//The criteria below, is returning clientId
DetachedCriteria eventCr = DetachedCriteria.forClass(Event.class, "event");
eventCr.setProjection(Projections.projectionList().add(Projections.groupProperty("clientId")).add(Projections.max("eventId")));
//Now using subqueries you can achieve your goal
criteria.add(Subqueries.propertyIn("clientId", eventCr));
I don't know for sure what you're looking for, but I hope I have given you some good hints. You might want to try Subqueries.propertyEq instead if your query must return a single id.
Related
I have a requirement for a Input record with id1 from source, in target table I need to update value v1 in column c1 and in target for id1 there are multiple records. Using JPA I need to update all those records with value v1. Using JPA what is the best way to do this?
I used below
findallbyid() then saveall() - it failed saying there are mutliple records in target but expected was one.
Based on the details provided findallbyid() then saveall()
here the method findallbyid() is actually expecting to find only one record in the table, where as there are multiple rows.
changing the to signature of the method should work as expected without expection. As it expect capitalised words in method signature
https://docs.spring.io/spring-data/jpa/docs/current/api/org/springframework/data/jpa/repository/JpaRepository.html
List<T> findAllById(Long id);
but recommend not to read all rows and then save again just to update a column or two, you could use something like below to achieve the same
#Modifying
#Transactional
#Query(value = "UPDATE table t SET t.column = :status WHERE t.id = :id")
int update(#Param("status") String status, #Param("id") Long id);
I'm working with JPQL, I want to remove all the duplicated rows using DISTINCT, and at the same time retrieve all the columns in a table, I wrote something like this:
SELECT DISTINCT cl.name, cl.age
FROM Client AS cl
WHERE cl.country='****'
This query returns just the two columns name and age.
Assuming you have a unique id you could write your query to use GROUP BY as follows:
SELECT client FROM Client client
WHERE client.id IN (
SELECT MIN(c.id)
FROM Client c
WHERE c.country='****'
GROUP BY c.name, c.age
)
You should not retrieve all the fields of Client because you should not select non-aggregated fields.
Try this :
DELETE from Client c
Where c.name IN (SELECT DISTINCT cl.name
FROM Client AS cl
WHERE cl.country='****')
But pay attention to your persistence context to avoid corrupt data.
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.
I'm building a select that has to get me all distinct values from a table.
The sql I would normally write would look like this: "SELECT DISTINCT ARTIST FROM MUSICLIB"
However, ebean is generating the following: "SELECT DISTINCT ID, ARTIST FROM MUSICLIB"
The finder is as such:
find.select("artist").setDistinct(true).findList();
I've found that ebean is generating this ID on every single query, no matter what options I set.
How do I accomplish what I'm looking for?
You can't do that, Ebean for objects mapping requires ID field, and if you won't include it you'll get some mysterious exceptions.
Instead you can query DB without mapping and then write your SQL statement yourself:
SqlQuery sqlQuery = Ebean.createSqlQuery("SELECT DISTINCT artist FROM musiclib");
List<SqlRow> rows = sqlQuery.findList();
for (SqlRow row : rows) {
debug("I got one: " + row.getString("artist"));
}
Of course if artist is a relation, you need to perform additional query using list of found IDs with in(...) expression.
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