2012-01-06 18 views
11

Estoy construyendo mi primera aplicación web Java EE usando Glassfish y JSF. Soy bastante nuevo en la consulta de criterios y tengo una consulta que debo realizar, pero el tutorial de javaee6 parece un poco escaso en los ejemplos. De todos modos, estoy teniendo dificultades para crear la consulta.Necesito ayuda para crear la consulta de criterios JPA

Objetivo: Quiero sacar a la compañía con la mayor cantidad de documentos almacenados. Las empresas tienen una relación de OneToMany con los documentos. Documents tiene una relación ManyToOne con varias tablas, la columna "usertype" las distingue.

MySQL consulta:

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

Gracias

--update-- base en la retroalimentación del usuario, esto es lo que tengo hasta ahora:

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

El error que consigo es :

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

¡Error típico, no significa nada para mí!

+0

Intente eliminar el tipeo de la consulta de CriteriaQuery a CriteriaQuery para seleccionar el recuento sin ofender la API. Si también publicas más información sobre las tablas/entidades, puedo probar otras formas. – perissf

Respuesta

20

Su consulta no devuelve un objeto completa entidad ya que sólo está seleccionando dos campos de la tabla dada (esta es la razón de que está recibiendo un error que dice yadayadapartialyadayada).

Su solución es casi correcta, esto es lo que necesita cambiar para que funcione, por lo que es parcial.

En lugar de una llanura CriteriaQuery<...> usted tiene que crear una tupla CriteriaQuery<..> llamando CriteriaBuilder.createTupleQuery(). (Básicamente, puede llamar CriteriaBuilder.createQuery(...) y pasar Tuple.class a ella como un argumento. Tuple es una especie de comodín clase entidad.)

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

(campos de Acceso de un Tuple me dio un error si yo no' t alias para ellos (en multiselect(...)) su uso. esta es la razón por que he usado alias, pero esto puede ser abordado de forma más limpia mediante el uso de JPA 2 Metamodel API, que se describe en la especificación bastante bien.)

La documentación para CriteriaQuery.multiselect(...) describe el comportamiento de consultas usando objetos Tuple más profundamente.

+0

¡Brillante! Funcionó con casi nada más sacarlo de la caja. Entre esto y el artículo @Mechkov compartido, entiendo mucho mejor las consultas de criterios. Gracias. –

+0

Una buena respuesta, ayudó a resolver mi problema con el siguiente error 'Debe usar dontMaintainCache()' – user75ponic

+0

Gracias por su ejemplo de código. Aprendí mucho sobre las consultas de criterios de jpa usando tuplas (en lugar de Entidades). – hbobenicio

0

Echa un vistazo a este sencillo tutorial. Utiliza JPA2 y Criterios

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

Saludos!

+1

El tutorial que has publicado está bien, pero la consulta que OP desea plantea una pregunta interesante: ¿es útil la API de Criteria cuando la consulta devuelve objetos de diferente tipos? – perissf

+0

gracias, el tutorial me ayudó mucho. En cuanto a los diferentes tipos, todo lo que necesito es el id (largo). –

+0

Cool. Me alegro de que haya ayudado. Lo usé yo mismo, no hace mucho tiempo. – Mechkov

2

Si está usando Hibernate, esto debería funcionar:

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

espero que ayude!

+0

Esto significa usar Hiberate, que está fuera del alcance aquí. Deberías al menos mencionar esto. – perissf

+0

sí, me temo que no estoy usando Hibernate. ¡aunque estoy empezando a desear serlo! –

+0

oh, grandes disculpas. ¡No me di cuenta de eso! – Gonzalo

Cuestiones relacionadas