Нужна помощь в создании запроса критериев JPA - PullRequest
11 голосов
/ 07 января 2012

Я создаю свое первое веб-приложение на Java EE, используя Glassfish и JSF. Я довольно новичок в запросе критериев, и у меня есть запрос, который мне нужно выполнить, но учебник по javaee6 кажется немного тонким на примерах. В любом случае, мне сложно создать запрос.

Цель: я хочу вывести компанию с наибольшим количеством документов. Компании имеют отношения OneToMany с Документами. Документы имеют отношение ManyToOne с несколькими таблицами, в столбце «тип пользователя» они различаются.

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().

Типичная ошибка, для меня ничего не значит!

Ответы [ 3 ]

21 голосов
/ 07 января 2012

Ваш запрос не возвращает завершенный объект сущности, так как вы выбираете только два поля данной таблицы (вот почему вы получаете сообщение об ошибке 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(...)). Вот почему я использовал псевдонимы, но это можно решить более аккуратно используя JPA 2 Metamodel API , который довольно подробно описан в спецификации. )

Документация для CriteriaQuery.multiselect(...) более детально описывает поведение запросов с использованием Tuple объектов.

2 голосов
/ 07 января 2012

Если вы используете 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"));

Надеюсь, это поможет!

0 голосов
/ 07 января 2012

Взгляните на этот простой урок. Он использует JPA2 и критерии

http://www.jumpingbean.co.za/blogs/jpa2-criteria-api

Привет! * * 1006

...