jpa criteria - expression based on db field name - java

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;

Related

how to write subquery using criteria

please help me out writing criteria builder for this query
SELECT *
FROM XYZ
WHERE date_v < "2020/01" AND
id NOT IN (SELECT id FROM XYZ WHERE date_v = '2020/01')
i have looked at using subqueries in jpa criteria api but i am unable to figure it
I have tried using subquery and joins but it throwing different error after all i get to know that i need to get more clarity about query criteria usages. any help much appreciated
You have to create XyzEntity with Long id and LocalDate date_v fields.
// query
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<XyzEntity> query = cb.createQuery(XyzEntity.class);
Root<XyzEntity> root = query.from(XyzEntity.class);
LocalDate date = LocalDate.of(2020, 1, 1);
// subquery
Subquery<Long> subQuery = query.subquery(Long.class);
Root<XyzEntity> subRoot = subQuery.from(XyzEntity.class);
Predicate idSubPredicate = cb.equal(root.get("id"), subRoot.get("id"));
Predicate dateSubPredicate = cb.equal(subRoot.get("date_v"), date);
subQuery.select(subRoot.get("id")).where(idSubPredicate, dateSubPredicate);
// query predicates
Predicate datePredicate = cb.greaterThan(root.get("date_v"), date);
Predicate notExistsPredicate = cb.exists(subQuery).not();
// query result
query.select(root).where(datePredicate, notExistsPredicate);
List<XyzEntity> result = entityManager.createQuery(query).getResultList();
I have mentioned the corrections in comments for the answer but I feel providing full solution seems good and helps others:
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Entity> query = cb.createQuery(Entity.class);
Root<Entity> root = query.from(Entity.class);
// subquery
Subquery<Long> subQuery = query.subquery(Long.class);
Root<Entity> subRoot = subQuery.from(Entity.class);
Predicate subPredicate = cb.equal(subRoot.get("date_v"), dateValue);
subQuery.select(subRoot.get("id")).where(subPredicate);
// query predicates
Predicate datePredicate = cb.lessThan(root.get("date_v"), dateValue);
Predicate notExistsPredicate = root.get("id").in(subQuery).not();
// query result
query.select(root).where(datePredicate, notExistsPredicate);
Query d = entityManager.createQuery(query);
List<Entity> resultList = d.getResultList()

Hibernate Criteria - Many to Many relations

I'm trying to use Hibernate Criteria for a select using tables related in a many-to-many relation. The n-m table has some additional columns not just the id's from each of the tables.
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<User> criteria = builder.createQuery(Fornecedor.class);
Root<User> root = criteria.from(User.class );
criteria.select(root);
root.fetch("userRolesList");
List<User> users = em.createQuery(criteria).getResultList();
In User class I have the userRolesList (n-m table) which has the roles. So I have User -> UserRoles -> Role. Every property are mapped as FetchType.LAZY
When I try to print the user roles, for example, hibernate throws the org.hibernate.LazyInitializationException cause the roles where not fetched.
When I change code for the one that follows.
code:
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<User> criteria = builder.createQuery(Fornecedor.class);
Root<User> root = criteria.from(User.class );
criteria.select(root);
root.fetch("userRolesList");
root.fetch("userRolesList.role");
List<User> users = em.createQuery(criteria).getResultList();
then I get:
java.lang.IllegalArgumentException: Unable to locate Attribute with
the the given name [userRolesList.role] on this ManagedType [User]
I have tryed many options for the situation like joins, but still couldn't make it work.
It seems you are trying to go a bit too far with the fetching.
Try doing it in baby steps:
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<User> criteria = builder.createQuery(Fornecedor.class);
Root<User> root = criteria.from(User.class );
criteria.select(root);
Fetch<User, UserRoles> userRolesFetch = root.fetch("userRolesList", JoinType.INNER);
Fetch<UserRoles, Role> roleFetch = userRolesFetch.fetch("role", JoinType.INNER);
List<User> users = em.createQuery(criteria).getResultList();

JPA Critera Query count results involving join

I'm using hibernate and the JPA criteria API and trying to create a re-usable utility method to determine how many rows a query will return.
Currently I have this:
Long countResults(CriteriaQuery cq, String alias){
CriteriaBuilder cb = em().getCriteriaBuilder();
CriteriaQuery<Long> countQuery = cb.createQuery(Long.class);
Root ent = countQuery.from(cq.getResultType());
ent.alias(alias);
countQuery.select(cb.count(ent));
Predicate restriction = cq.getRestriction();
if(restriction != null){
countQuery.where(restriction);
}
return em().createQuery(countQuery).getSingleResult();
}
Which I use like this:
CriteriaBuilder cb = em().getCriteriaBuilder();
CriteriaQuery<User> cq = cb.createQuery(User.class);
Root<User> root = cq.from(modelClass());
root.alias("ct");
cq.select(root);
TypedQuery<User> query = em().createQuery(cq);
long count = countResults(cq, "ct");
And that works fine.
However, when I use a more complicated query like
Join<UserThing, Thing> j = root.join(User_.things).join(UserThing_.thing);
cq.where(somePredicate);
My call to countResults() produces exceptions like org.hibernate.hql.internal.ast.InvalidPathException: Invalid path: 'myAlias.name', <AST>:0:0: unexpected end of subtree, left-hand operand of a binary operator was null
I'm guessing this has something to do with the join, and that I need to alias that somehow, but I've not had any success so far.
Help?
I had the same problem, and I solved with:
CriteriaQuery<Long> countCriteria = cb.createQuery(Long.class);
Root<EntityA> countRoot = countCriteria.from(cq.getResultType());
Set<Join<EntityA, ?>> joins = originalEntityRoot.getJoins();
for (Join<EntityA, ?> join : joins) {
countRoot.join(join.getAttribute().getName());
}
countCriteria.select(cb.count(countRoot));
if(finalPredicate != null)
countCriteria.where(finalPredicate);
TypedQuery<Long> queryCount = entityManager.createQuery(countCriteria);
Long count = queryCount.getSingleResult();
Where
originalEntityRoot is the main root where I did the query with the where clauses.

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.

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