Нужна помощь в создании запроса критериев JPA
Я создаю свое первое веб-приложение Java EE с помощью Glassfish и JSF. Я новичок в критерии запроса, и у меня есть запрос, который мне нужно выполнить, но учебник javaee6 кажется немного тонким на примерах. Во всяком случае, мне сложно создавать запрос.
Цель: Я хочу вытащить компанию с сохраненными документами.
У компаний есть отношения OneToMany с документами.
Документы имеют отношения ManyToOne с несколькими таблицами, столбец "usertype" различает их.
Запрос MySQL:
SELECT USERID, COUNT(USERID) AS CNT
FROM DOCUMENTS
WHERE USERTYPE="COMPANY"
GROUP BY USERID
ORDER BY CNT DESC
Спасибо
- update--
Основываясь на отзывах пользователей, вот что я до сих пор:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Documents> cqry = cb.createQuery(Documents.class);
//Intersting Stuff
Root<Documents> root = cqry.from(Documents.class);
Expression userid = root.get("userID");
Expression usertype = root.get("userType");
Expression count = cb.count(userid);
cqry.multiselect(userid, count);
Predicate userType = cb.equal(usertype, "COMPANY");
cqry.where(userType);
cqry.groupBy(userid);
cqry.orderBy(cb.desc(count));
//more boilerplate
Query qry = em.createQuery(cqry);
List<Documents> results = qry.getResultList();
Ошибка, которую я получаю:
Exception Description: Partial object queries are not allowed to maintain the cache or be edited. You must use dontMaintainCache().
Типичная ошибка, для меня ничего не значит!
Ответы
Ответ 1
Ваш запрос не возвращает полный объект сущности, поскольку вы выбираете только два поля данной таблицы (вот почему вы получаете сообщение об ошибке yadayadapartialyadayada).
Ваше решение почти правильно, вот что вам нужно изменить, чтобы заставить его работать, делая его частичным.
Вместо простого CriteriaQuery<...>
вам нужно создать кортеж CriteriaQuery<..>
, вызвав CriteriaBuilder.createTupleQuery()
. (В принципе, вы можете вызвать CriteriaBuilder.createQuery(...)
и передать Tuple.class
в качестве аргумента. Tuple
- это своего рода класс подстановочных сущностей.)
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Tuple> cq= cb.createTupleQuery();
Root<Documents> root = cq.from(Documents.class);
Expression<Integer> userId = root.get("USERID");
Expression<String> userType = root.get("USERTYPE");
Expression<Long> count = cb.count(userId);
cq.multiselect(userId.alias("USERID"), count.alias("CNT"));
cq.where(cb.equal(userType, "COMPANY");
cq.groupBy(userId);
cq.orderBy(cb.desc(count));
TypedQuery<Tuple> tq = em.createQuery(cq);
for (Tuple t : tq.getResultsList()) {
System.out.println(t.get("USERID"));
System.out.println(t.get("CNT"));
}
(Доступ к полям Tuple
дал мне ошибку, если я не использовал для них псевдонимы (в multiselect(...)
). Вот почему я использовал псевдонимы, но это можно решить более чисто с использованием API JPA 2 Metamodel API, который подробно описан в спецификации.)
В документации для CriteriaQuery.multiselect(...)
более подробно описывается поведение запросов с использованием объектов Tuple
.
Ответ 2
Если вы используете Hibernate, это должно работать:
ProjectionList pl = Projections.projectionList()
.add(Projections.groupProperty("userid"))
.add(Projections.property("userid"))
.add(Projections.count("userid"));
Criteria criteria = session.createCriteria(Document.class)
.add(Restrictions.eq("usertype",usertype))
.setProjection(pl)
.addOrder(Order.desc("cnt"));
Надеюсь, что это поможет!
Ответ 3
Взгляните на этот простой учебник. Он использует JPA2 и критерии
http://www.jumpingbean.co.za/blogs/jpa2-criteria-api
Привет!