I try do the folow JPQL clause to criteria Api
SELECT new ProductDTOOut(p.id,p.name,
(SELECT pr.price FROM Price pr WHERE pr.product.id = p.id and pr.company.id = :companyId) )
FROM Product p
without success,
how can I do it ?
tnx advanced
I know solve my problem follow answer :
CriteriaBuilder cb = manager.getCriteriaBuilder();
CriteriaQuery<ProductDTOOut> criteriaQuery = cb.createQuery(ProductDTOOut.class);
// create query
Root<Product> rootFrom = criteriaQuery.from(Product.class);
// creating subquery
Subquery<Double> subquery = criteriaQuery.subquery(Double.class);
Root<Price> subqueryRoot = subquery.from(Price.class);
subquery.select(subqueryRoot.get(Price_.PRICE));
subquery.where(
cb.equal(rootFrom.get(Product_.ID),
subqueryRoot.get(Price_.PRODUCT).get(Product_.ID)),
cb.equal(
subqueryRoot.get(Price_.COMPANY).get(Company_.ID), companyId));
criteriaQuery.select(cb.construct(ProductDTOOut.class,
rootFrom.get(Product_.ID),
rootFrom.get(Product_.NAME),
subquery // here put subquery
));
TypedQuery<ProductDTOOut> query = manager.createQuery(criteriaQuery);
return query.getResultList();
I hope that I helped someone with the same question.
Related
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()
I'm trying to write a CriteriaQuery which will query latest observation for each city. City is defined by city_code field, while latest record is defined by observation_time field.
I can easily write it in a plain SQL, but I cant understand how to do it with jpa criteria api.
select distinct m.* from
(select city_code cc, max(observation_time) mo
from observations group by city_code) mx, observations m
where m.city_code = mx.cc and m.observation_time = mx.mo`
It is possible when You are open for loose efficiency.
So first let's transform our query to logical equivalent one:
select distinct m.* from observations m where
m.observation_time = (select max(inn. observation_time) from observations inn
where inn.city_code = m.city_code);
then let's translate it to JPA CriteriaQuery:
public List<Observation> maxForEveryWithSubquery() {
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Observation> query = builder.createQuery(Observation.class);
Root<Observation> observation = query.from(Observation.class);
query.select(observation);
Subquery<LocalDateTime> subQuery = query.subquery(LocalDateTime.class);
Root<Observation> observationInner = subQuery.from(Observation.class);
subQuery.where(
builder.equal(
observation.get(Observation_.cityCode),
observationInner.get(Observation_.cityCode)
)
);
Subquery<LocalDateTime> subSelect = subQuery.select(builder.greatest(observationInner.get(Observation_.observationTime)));
query.where(
builder.equal(subSelect.getSelection(), observation.get(Observation_.observationTime))
);
TypedQuery<Observation> typedQuery = entityManager.createQuery(query);
return typedQuery.getResultList();
}
Unfortunately JPA does not support sub queries in FROM clause. You need to write a native query or use framework like FluentJPA.
I want to create a typed query.
TypedQuery<PubThread> query = em.createQuery(queryString, PubThread.class);
query.setParameter("threadId", threadId);
List<PubThread> otherPubThreads = query.getResultList();
In the queryString is the following SQL (currently without param and static selection values)
SELECT pt2 FROM pubthread pt2
JOIN pub_pubthread ppt2 ON pt2.id = ppt2.pubThreads_id
JOIN pub p2 ON ppt2.pups_id = p2.id
JOIN pubcategory pc2 ON p2.pubCategoryId = pc2.id
WHERE pt2.id != 1 and EXISTS (
SELECT DISTINCT(pt.id)
FROM pubthread pt
JOIN pub_pubthread ppt ON pt.id = ppt.pubThreads_id
JOIN pub p ON ppt.pups_id = p.id
JOIN pubcategory pc ON p.pubCategoryId = pc.id
WHERE pc2.id = pc.id and pt.id = 1
)
It does work, if I limit the String to a simple select: SELECT Distinct(pt2.id), pt2.name FROM pubthread pt2. As soon I add a JOIN line to it, it will complain. How do you properly query with JOINS in JPA? The error is:
org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token: ON near line 1, column 81 [SELECT pt2 FROM com.brayan.webapp.model.PubThread pt2 JOIN pub_pubthread ppt2 ON pt2.id = ppt2.pubThreads_id ]
Doubtless, a criteria query would be nicer. I accept that as part of the solution space.
When you call createQuery you have to write HQL but not SQL (your queryString is not HQL).
In HQL you have to join objects according to your mapping entities.
If you sill need SQL query use createNativeQuery method.
See documentation about how to create HQL query.
Got it. See below a fully example of joins. It consists of:
multiple joins (join-chaining)
a subquery
a predicate correlation/equation over join tables, other than the root table.
I also commented the obsolete code lines for other to see what a wrong approach.
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery mainQuery = criteriaBuilder
.createQuery(PubThread.class);
// 1) MainQuery
// Create the FROM
Root<PubThread> rootPubThread = mainQuery.from(PubThread.class);
// Create the JOIN from the first select: join-chaining. You only need the return for ordering. e.g. cq.orderBy(cb.asc(categoryJoin.get(Pub_.title)));
Join<Pub, PubCategory> categoryJoin = rootPubThread.join(PubThread_.pups).join(Pub_.pubCategory);
// Create the WHERE
mainQuery.where(criteriaBuilder.not(criteriaBuilder.equal(rootPubThread.get(PubThread_.id), threadId)));
// Create the SELECT, at last
mainQuery.select(rootPubThread).distinct(true);
// 2) Subquery
Subquery<PubThread> subquery = mainQuery.subquery(PubThread.class);
Root<PubThread> rootPubThreadSub = subquery.from(PubThread.class);
//subquery.where(criteriaBuilder.equal(rootPubThread.get(PubThread_.id), threadId));
Join<Pub, PubCategory> categoryJoinSub = rootPubThreadSub.join(PubThread_.pups).join(Pub_.pubCategory);
subquery.select(rootPubThreadSub);
//Predicate correlatePredicate = criteriaBuilder.equal(rootPubThreadSub.get(PubThread_.id), rootPubThread);
Predicate correlatePredicate = criteriaBuilder.and(
//criteriaBuilder.equal(rootPubThreadSub.get(PubThread_.id), rootPubThread),
criteriaBuilder.equal(categoryJoinSub.get(PubCategory_.id), categoryJoin.get(PubCategory_.id)),
criteriaBuilder.equal(rootPubThreadSub.get(PubThread_.id), threadId)
);
subquery.where(correlatePredicate);
//Predicate correlatePredicate = criteriaBuilder.equal(rootPubThreadSub.get(PubThread_.id), rootPubThread);
Predicate mainPredicate = criteriaBuilder.and(
criteriaBuilder.not(criteriaBuilder.equal(rootPubThread.get(PubThread_.id), threadId)),
criteriaBuilder.exists(subquery)
);
//cq.where(criteriaBuilder.exists(subquery));
mainQuery.where(mainPredicate);
I have following jpa criteria query:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Company> cq = cb.createQuery(Company.class);
Root<Company> root = cq.from(Company.class);
cq.select(root);
Subquery<String> sq = cq.subquery(String.class);
Root<Employee> subroot = sq.from(Employee.class);
sq.select(subroot.get(Employee_.lastName));
Predicate typePredicate = cb.equal(subroot.get(Employee_.lastName), "Doe");
Predicate correlatePredicate = cb.equal(root.get(Company_.employees), subroot);
sq.where(cb.and(typePredicate, correlatePredicate));
cq.where(cb.exists(sq));
TypedQuery<Company> typedQuery = em.createQuery(cq);
List<Company> companies = typedQuery.getResultList();
Eclipselink produces following SQL:
SELECT t0.ID, ... FROM COMPANY t0
WHERE EXISTS (SELECT t1.LASTNAME FROM EMPLOYEES t2, EMPLOYEES t1
WHERE (((t1.LASTNAME = ?) AND (t1.ID = t2.ID))
AND (t2.COMPANY_ID = t0.ID)))
As you can see there is an unneccessary join on table EMPLOYEES. How do I get rid of this join?
You don't seem to need a subquery for the query, just a join should be enough,
http://en.wikibooks.org/wiki/Java_Persistence/Criteria#Join
Otherwise, what version are you using? Can you try EclipseLink 2.4.
If it still has the duplicate, please log a bug and vote for it.
You might be able to use the inverse ManyToOne, instead of the OneToMany (i.e. root == subroot.get("company") ).
Also try JPQL in 2.4, is the join optimized?
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();