2011-01-11 38 views
8

que estoy tratando, como en el título, para insertar una subconsulta en la cláusula select como en esta sencilla SQL:subconsulta en la cláusula select con API JPA Criterios

SELECT id, name, (select count(*) from item) from item 

esto es, obviamente, sólo una consulta simulada sólo para hacer mi punto. (El punto sería la de obtener la última factura para cada artículo devuelto por la consulta.)

He intentado esto:

CriteriaBuilder cb = em.getCriteriaBuilder(); 
CriteriaQuery<Tuple> c = cb.createTupleQuery(); 
Root<Item> item= c.from(Item.class); 

Subquery<Long> scount = c.subquery(Long.class); 
Root<Item> sarticolo = scount.from(Item.class); 
scount.select(cb.count(sitem)); 

c.multiselect(item.get("id"),item.get("nome"), scount); 

Query q = em.createQuery(c); 
q.setMaxResults(100); 
List<Tuple> result = q.getResultList(); 

for(Tuple t: result){ 
    System.out.println(t.get(0) + ", " + t.get(1) + ", " + t.get(2)); 
} 

pero solo me dan:

java.lang .IllegalStateException: La subconsulta no puede ocurrir en la cláusula de selección

¿Cómo puedo obtener un resultado similar?

Respuesta

10

Es compatible con JPA 2.1 e Hibernate 5.0. Solo debe agregar getSelection() al argumento de subconsulta en el multiselect de la consulta principal.

c.multiselect(item.get("id"),item.get("nome"), scount.getSelection()); 

Tome un vistazo a este ejemplo de trabajo:

CriteriaBuilder builder = em.getCriteriaBuilder(); 
CriteriaQuery<NotificationInfo> cq = builder.createQuery(NotificationInfo.class); //wrapper class 
Root<Notification> n = cq.from(Notification.class); //root entity 

//Subquery 
Subquery<Long> sqSent = cq.subquery(Long.class); 
Root<NotificationUser> sqSentNU = sqSent.from(NotificationUser.class); 
sqSent.select(builder.count(sqSentNU)); 
sqSent.where(
     builder.equal(sqSentNU.get(NotificationUser_.notification), n), //join subquery with main query 
     builder.isNotNull(sqSentNU.get(NotificationUser_.sendDate)) 
); 

cq.select(
    builder.construct(
      NotificationInfo.class, 
      n.get(Notification_.idNotification), 
      n.get(Notification_.creationDate), 
      n.get(Notification_.suspendedDate), 
      n.get(Notification_.type), 
      n.get(Notification_.title), 
      n.get(Notification_.description), 
      sqSent.getSelection() 
    ) 
); 
em.createQuery(cq).getResultList(); 
6

JPA no admite subconsultas en la cláusula de selección.

Necesita cambiar su consulta para no utilizarla, requerir la subconsulta en la cláusula de selección, ejecutar múltiples consultas o utilizar una consulta SQL nativa.

2

JPA ahora admite subconsultas en la cláusula de selección.

EDIT:
JPA 2.1 JPQL BNF admite subconsultas en la cláusula de selección, incluso si no es necesario. Por lo que sé, Eclipselink admite esto e Hibernate también (probado en 5.1).

+1

Exactamente qué versión de APP Especificación significa la palabra "ahora" en su respuesta significa? –

+0

"ahora" significaba exactamente la última versión de JPA que era (es) 2.1 –

1

Es necesario fusionar el resultado de subconsulta:

Expression<ResultType> expression = criterioaBuilder.coalesce(subquery, criteriaBuilder.literal((ResultType) defaultResult); 
query.select(expression); 
Cuestiones relacionadas