2012-01-06 19 views
11

Buduję swoją pierwszą aplikację internetową Java EE przy użyciu Glassfish i JSF. Jestem dość nowy w zapytaniu o kryteria i mam kwerendę, którą muszę wykonać, ale samouczek javaee6 wydaje się trochę cienki na przykładach. W każdym razie trudno mi jest utworzyć zapytanie.Potrzebujesz pomocy w tworzeniu zapytania o kryteria JPA

Cel: Chcę pobrać firmę z największą ilością przechowywanych dokumentów. Firmy mają OneToany związek z dokumentami. Dokumenty mają związek ManyToOne z kilkoma tabelami, kolumna "usertype" je rozróżnia.

zapytań MySQL:

SELECT USERID, COUNT(USERID) AS CNT 
FROM DOCUMENTS 
WHERE USERTYPE="COMPANY" 
GROUP BY USERID 
ORDER BY CNT DESC 

Dzięki

--update-- oparciu o opinie użytkowników, tutaj jest to, co mam tak daleko:

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

Błąd pojawia się :

Exception Description: Partial object queries are not allowed to maintain the cache or be edited. You must use dontMaintainCache(). 

Typowy błąd, nic dla mnie nie znaczy!

+0

Spróbuj odeprzeć zapytanie z CriteriaQuery do CriteriaQuery, aby wybrać liczbę bez obrażania interfejsu API. Jeśli publikujesz więcej informacji o tabelach/obiektach, mogę wypróbować inne sposoby. – perissf

Odpowiedz

20

Zapytanie nie zwraca kompletnego obiektu jednostki jak jesteś wybierając tylko dwa pola w danej tabeli (jest to dlaczego jesteś otrzymuję błąd, który mówi yadayadapartialyadayada).

Twoje rozwiązanie jest prawie w porządku, oto, co musisz zmienić, aby działało, czyniąc to częściowym.

Zamiast zwykłego CriteriaQuery<...> trzeba stworzyć krotkiCriteriaQuery<..> wywołując CriteriaBuilder.createTupleQuery(). (W zasadzie, można zadzwonić CriteriaBuilder.createQuery(...) i przekazać Tuple.class do niej jako argument. Tuple jest rodzajem wieloznacznym klasy podmiotu.)

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")); 
} 

(Dostęp polach Tuple dał mi błąd, gdybym nie zrobił” t aliasy dla nich (w multiselect(...)) stosowanie. to dlatego użyłem aliasy, ale można to rozwiązać w bardziej elegancki sposób za pomocą JPA 2 za metamodel API, który jest opisany w specyfikacji dość dokładnie.)

Dokumentacja dla CriteriaQuery.multiselect(...) opisuje bardziej szczegółowo zachowanie zapytań z obiektami Tuple.

+0

Genialny! To działało niemal natychmiast po wyjęciu z pudełka. Pomiędzy tym a artykułem @Mechkov udostępniłem znacznie lepiej rozumiem zapytania o kryteria. Dziękuję Ci. –

+0

Dobra odpowiedź, pomogła rozwiązać mój problem z następującym błędem 'Musisz użyć dontMaintainCache()' – user75ponic

+0

Dzięki za przykład twojego kodu. Nauczyłem się dużo o zapytaniach o kryteria jpa, używając do tego krotek (zamiast jednostek). – hbobenicio

0

Zapoznaj się z tym prostym samouczkiem. Wykorzystuje JPA2 i kryteria

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

Pozdrawiam!

+1

Opublikowany tutorial jest w porządku, ale zapytanie, które OP chce, rodzi interesujące pytanie: czy API Criteria naprawdę przydaje się, gdy zapytanie zwraca obiekty różnych typy? – perissf

+0

dzięki, tutorial bardzo mi pomógł. Jeśli chodzi o różne typy, potrzebuję tylko id (long). –

+0

Cool. Cieszę się, że to pomogło. Użyłem tego sam, nie tak dawno temu. – Mechkov

2

Jeśli używasz hibernacji, to powinno działać:

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")); 

Nadzieję, że to pomaga!

+0

Oznacza to użycie Hiberate, który jest poza zakresem. Powinieneś przynajmniej o tym wspomnieć. – perissf

+0

tak, obawiam się, że nie używam Hibernate. choć zaczynam żałować, że nie jestem! –

+0

oh, wielkie przeprosiny. Nie zdawałem sobie z tego sprawy! – Gonzalo

Powiązane problemy