JPA Criteria with ElementCollection - java

I have something like that:
#Entity
public class Person {
#ElementCollection
private List<String> emails;
...
}
how can I convert the following JPQL into a Criteria Query:
select p from Person p
where exists (
select 1
from p.emails e
where e like :email
)

If you don't really need the power of LIKE and an exact match is enough you can check if emails contains email.
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Person> criteria = builder.createQuery(Person.class);
Root<Person> p = criteria.from(Person.class);
criteria.select(p);
Expression<List<String>> emails = p.get(Person_.emails);
criteria.where(builder.isMember("[email address]", emails));
TypedQuery<Person> tq = entityManager.createQuery(criteria);
List<Person> persons = tq.getResultList();
Note that p.get(Person_.emails) requires a static meta model of the Person class. If you do not have that, you can replace that part by p.get("emails") at the cost of type-safety.
If you do need to perform a LIKE you will have to join on the collection.
Join<Person, String> emailJoin = p.join(Person_.emails);
criteria.where(builder.like(emailJoin, "[email address]"));
criteria.distinct(true);

Related

Order list by max date of a children (using Hibernate Critéria)

I'm trying to sort a list by the max date of a children class, using hibernate criteria:
Domain:
class Entity {
List<Children> childrens;
}
class Children {
Date date
}
Something like this in SQL:
SELECT
*
FROM
entity
INNER JOIN
children c1 ON c1.entity_id = entity.id
WHERE
c1.date =
(SELECT MAX(c2.date) FROM children c2 WHERE c2.entity_id = c1.entity_id)
ORDER BY
c1.date DESC
Does anyone know how to do this?
You can formulate something like that with HQL or the JPA Criteria API. Here is the HQL version:
from
Entity e
order by
(select max(c.date) from e.children c) desc
or with the Criteria API:
CriteriaBuiler cb = em.getCriteriaBuilder();
CriteriaQuery<Entity> q = cb.createQuery(Entity.class);
Root<Entity> r = q.from(Entity.class);
Subquery<Date> s = q.subquery(Date.class);
Join<?, ?> c = s.correlate(r).join("children");
s.select(cb.max(c.get("date")));
q.orderBy(cb.desc(s));
List<Entity> list = em.createQuery(q).getResultList();

jpa criteria - expression based on db field name

I have an entity called User, which has the following relationship to an entity called Company:
#Entity
public class User {
...
#ManyToOne
#JoinColumn(name="COMPANY_ID",referencedColumnName="ID")
private Company company = null;
...
}
And on my database, I have a User table with a "COMPANY_ID" column. How can I create a JPA criteria query using this field?
Using a criteria builder, I've tried the following expressions without success:
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery cq = cb.createQuery(User.class);
Root mockEntityRoot = cq.from(User.class);
//cq.where(cb.equal(mockEntityRoot.get("company"), 2));
//cq.where(cb.equal(mockEntityRoot.get("COMPANY_ID"), 12));
cq.where(cb.equal(mockEntityRoot.get("company.id"), 8));
entityManager.createQuery(cq).getResultList();
But I got the following error: "The attribute [company.id] from the managed type User is not present."
Thanks in advance.
I think you need an explicit join.
Notice I am using Criteria's metamodel.
This is a snippet I have, it's not the same thing as yours but you can have an idea
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Site> q = cb.createQuery(Site.class);
Root<Site> e = q.from(Site.class);
Join<Site,SiteType> siteType = e.join(Site_.siteType);
Predicate predicate = cb.conjunction();
Predicate p1 = cb.equal(siteType.get(SiteType_.id), selectedSiteType.getId());
Predicate p2 = cb.equal(e.get(Site_.markedAsDeleted), false);
predicate = cb.and(p1,p2);
q.where(predicate);
q.select(e);
TypedQuery<Site> tq = entityManager.createQuery(q);
List<Site> all = tq.getResultList();
return all;

JPA(2.0) Criteria Simple Join

I am having problem creating criteriaQuery for the following sql.
Any help would be appreciated.Lets say I have two tables Member and Person.
I am joining on name and age and having where clause for both of the table.
I am using OpenJPA(2.0)
select *
from Member
join Person
on Member.name = Person.name
and Member.age = Person.age
where Member.name = 'someOne'
and Member.age = '24'
and Person.gender = 'F'
and Person.type = 'employee'
How about something like this:
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Tuple> criteria = builder.createTupleQuery();
Root<Member> fromMember = criteria.from(Member.class);
Root<Person> fromPerson = criteria.from(Person.class);
criteria.multiselect(fromMember, fromPerson);
List<Predicate> predicates = new ArrayList<Predicate>();
predicates.add(builder.equal(fromMember.get(Member_.name), fromPerson.get(Person_.name)));
predicates.add(builder.equal(fromMember.get(Member_.age), fromPerson.get(Person_.age)));
predicates.add(builder.equal(fromMember.get(Member_.name), "someOne"));
predicates.add(builder.equal(fromMember.get(Member_.age), 24));
predicates.add(builder.equal(fromPerson.get(Person_.gender), "F"));
predicates.add(builder.equal(fromPerson.get(Person_.type), "employee"));
criteria.where(predicates.toArray(new Predicate[predicates.size()]));
List<Tuple> result = em.createQuery(criteria).getResultList();
This will return a 2-element tuple made up of Member and Person. You can enumerate the individual fields in the call to multiselect if you would rather have individual fields in each tuple.

JPA 2.0 CriteriaBuilder help - How do I select the Greatest(max) value that matches a certain where query?

Sorry for this rather basic question, but I have to get some sort of prototype working very quickly and this is my first foray into JPA.
I have a class, System that has a List of Snapshot items, each has a numeric ID, and a SystemID.
How do I query Snapshots to say something like:
select top 1 ID from Snapshots
where Snapshots.SystemID = X
order by Snapshots.ID desc;
I know how to put the where query in, not sure where to put my "greatest" bit.
Thanks!!
public Snapshot GetMostRecentSnapshotByID(int systemID) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<mynamespace.Snapshot> criteria =
cb.createQuery(mynamespace.Snapshot.class);
Root<mynamespace> snapshot = criteria.from(mynamespace.Snapshot.class);
criteria.where(cb.equal(snapshot.get(Snapshot_.systemID), systemID));
//OK -- where does this guy go?
cb.greatest(snapshot.get(Snapshot_.id));
return JPAResultHelper.getSingleResultOrNull(em.createQuery(criteria));
}
Clarification: I have the following (snippet) of my snapshot class
#
Entity
public class Snapshot implements Serializable {
#Id
#GeneratedValue
private int id;
#ManyToOne
#JoinColumn(name = "systemID", nullable = false)
private System system;
Can I query against a numerical id, vs using a System object, to find a particular System's snapshots?
Sorry if that was confusing!
You are a bit confused about jpa working with entities and properties instead of tables and columns; if you are learning I suggest you to first try to implement your query using jpql, something like:
String q = "from Snapshot s where s.systemID = :systemID order by s.id desc";
TypedQuery<Snapshot> query = em.createTypedQuery(q, Snapshot.class);
query.setParameter("systemID", systemID);
return query.getFirstResult();
// return a Snapshot object, get the id with the getter
(it would have been better to map (#OneToMany) Snapshot to System entity instead of using primitive ID)
then you could make a try with CriteriaBuilder (not using metamodel here):
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Object> cq = cb.createQuery();
Root<Snapshot> r = cq.from(Snapshot.class);
cq.where(cb.equal(r.get("systemID"), systemID));
cd.orderBy(cb.desc(r.get("id")));
em.createQuery(cq).geFirsttResult();
if you wanted to make a where...and... (but it's not your case in this question), it would have been:
[...]
Predicate p1 = cb.equal(r.get("systemID"), systemID));
Predicate p2 = cb. /* other predicate */
cb.and(p1,p2);
[...]
EDIT:
Can I query against a numerical id, vs using a System object, to find
a particular System's snapshots?
Sure, you can do it like that (given that System has an #Id property named id):
String q = "from Snapshot s where s.system.id = :systemID order by s.id desc";
[...]
where s.system.id means: property id (integer) of the property system (class System) of s (Snapshot).
Or, if you had the System entity, you could compare directly the objects:
String q = "from Snapshot s where s.system = :system order by s.id desc";
query.setParameter("system", system);
[...]
Using CriteriaBuilder (and metamodel):
Metamodel m = em.getMetamodel();
Root<Snapshot> snapshot = cq.from(Snapshot.class);
Join<Snapshot, System> system = snapshot.join(Snapshot_.system);
cq.where(cb.equal(System_.id, systemID));
[...]

Equivalent criteria query for named query

My named query looks like this, thanks to here.
#NamedQuery(
name="Cat.favourites",
query="select c
from Usercat as uc
inner join uc.cat as c
where uc.isFavourtie = true
and uc.user = :user")
And the call to implement looks like this :
Session session = sessionFactory.getCurrentSession();
Query query = session.getNamedQuery("Cat.favourites");
query.setEntity("user", myCurrentUser);
return query.list();
What would be the equivalent criteria query that returns a list of cats ?
With JPA 2.0 Criteria:
(This is one of the many ways you can achieve this using JPA 2.0 Criteria api)
final CriteriaQuery<Cat> cq = getCriteriaBuilder().createQuery(Cat.class);
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
final Root<Usercat> uc= cq.from(Usercat.class);
cq.select(uc.get("cat");
Predicate p = cb.equal(uc.get("favourtie", true);
p = cb.and(p, cb.equal(uc.get("user"), user));
cq.where(p);
final TypedQuery<Cat> typedQuery = entityManager.createQuery(cq);
return typedQuery.getResultList();

Categories