2011-01-11 17 views
8

Ich versuche, wie in Titel, eine Unterabfrage in select-Klausel wie in dieser einfachen SQL einzufügen:Subquery in select-Klausel mit JPA Criteria API

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

das ist natürlich nur eine Mock-Abfrage nur zu machen mein Punkt. (Der Punkt wäre die letzte Rechnung zu bekommen für jedes Element von der Abfrage zurückgegeben.)

ich das versucht habe:

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

aber ich bekomme nur:

java.lang .IllegalStateException: Unterabfrage kann nicht in Select-Klausel

Wie kann ich ein ähnliches Ergebnis erhalten?

Antwort

10

Es wird in JPA 2.1 und Hibernate 5.0 unterstützt. Sie mussten nur getSelection() zu dem Unterabfrageargument in der multiselect der Hauptabfrage hinzufügen.

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

bei diesem Arbeitsbeispiel Werfen Sie einen Blick:

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 unterstützt keine Unterabfragen in der SELECT-Klausel.

Sie müssen entweder Ihre Abfrage ändern, um die Sub-Abfrage in der SELECT-Klausel nicht verwenden zu müssen, mehrere Abfragen auszuführen oder eine systemeigene SQL-Abfrage zu verwenden.

2

JPA unterstützt nun Unterabfragen in der SELECT-Klausel.

EDIT:
JPA 2.1 JPQL BNF unterstützt Unterabfragen in Select-Klausel, auch wenn es nicht erforderlich ist. Soweit ich weiß, unterstützt Eclipselink dies auch und Hibernate (getestet in 5.1).

+1

genau, welche Version von JPA-Spezifikation bedeutet das Wort "jetzt" in Ihrem Antwort bedeuten? –

+0

"Jetzt" bedeutete genau die neueste Version von JPA, die war (ist) 2.1 –

1

Sie benötigen eine Unterabfrage Ergebnis zu verschmelzen:

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