2014-12-31 9 views
6

Dies ist ein Beispiel Einheit:JPA Kriterien Abfragegruppe von Anwendungen nur die ID

public class Account{ 

    @Id 
    Long id 
    Double remaining; 
    @ManyToOne 
    AccountType type 
} 

public class AccountType{ 
    @Id 
    Long id; 
    String name; 
} 

Jetzt erstelle ich eine Kriterien-Abfrage mit Join als follwing:

CriteriaBuilder criteriaBuilder = getEntityManager().getCriteriaBuilder(); 
CriteriaQuery criteriaQuery = criteriaBuilder.createquery(); 
Root<Account> accountRoot = criteriaQuery.from(Account.class); 
Join<Account, AccountType> typeJoin = accountRoot.join(Account_.type); 

criteriaQuery.multiSelect(
    typeJoin, 
    criteriaBuilder.sum(accountRoot.get(Account_.remaining)) 
); 

criteriaQuery.groupBy(typeJoin); 
Query query = getEntityManager().createQuery(criteriaQuery); 
query.getResultList(); 

Der obige Code wie SQL-Befehl erzeugen folgende:

select accType.id, accType.name, sum(acc.remaining) 
from account acc join accType on acc.accounttype_id = accType.id 
group by accType.id 

Above Code Arbeit in PosgreSQL kann aber in Oracle nicht ausgeführt, weil in ihm accType.name auswählen, die doesn tauche nicht in der group by-Klausel auf.

aktualisieren:
Ich denke, meine Frage ist nicht klar für Sie. Meine Frage betrifft nicht das PostgreSQL- oder Oracle-Verhalten in group by. Meine Frage ist diese:
Ich verwende typeJoin in group by Klausel (das heißt, ich erwarte Winterschlaf verwenden Sie alle Felder von AccountType in group by), aber warum Hibernate nur Identitätsfeld auf group by verwenden? wenn ich in group by nur Identitätsfeld verwenden, dann kann ich die folgende Anweisung:

criteriaQuery.groupBy(typeJoin.get(AccountType_.id)) ; 

Antwort

6

JPA/Hibernate nicht automatisch schließt alle Elementeigenschaften in einer Gruppe von Klausel, so müssen Sie sie manuell angeben:

CriteriaBuilder criteriaBuilder = getEntityManager().getCriteriaBuilder(); 
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(); 
Root<Account> accountRoot = criteriaQuery.from(Account.class); 
Join<Account, AccountType> typeJoin = accountRoot.join(Account_.type); 

criteriaQuery.multiSelect(
    typeJoin.get("id"), 
    typeJoin.get("name"), 
    criteriaBuilder.sum(accountRoot.get(Account_.remaining)) 
); 

criteriaQuery.groupBy(typeJoin.get("id"), typeJoin.get("name")); 
Query query = getEntityManager().createQuery(criteriaQuery); 
query.getResultList(); 
+0

das ist keine gute Idee. In dieser Lösung änderte sich der AccountType jedes Mal, wenn ich meine Abfragen ändere. Natürlich kann ich damit umgehen, aber ich denke, es muss eine bessere Lösung dafür geben. Sind Sie sicher, dass der Ruhezustand nicht alle Eigenschaften enthalten kann? –

+0

Sie können einfach die accountType.id angeben und anschließend einen Cache der zweiten Ebene verwenden, um sie zu laden. –

+0

Sie könnten natürlich auch das JPA-Metamodell verwenden, um alle Attribute des Entitätstyps abzurufen und sie in die Gruppe aufzunehmen, die generisch wäre. –

3

Wenn Sie GROUP BY verwenden, erfordert Oracle, dass jede Spalte in der Auswahlliste in GROUP BY enthalten ist.
PostgreSQL ist das gleiche, außer wenn nach dem Primärschlüssel gruppiert wird, dann können Sie eine beliebige Spalte auswählen.

Von Oracle docs

In einer Abfrage eine GROUP BY-Klausel enthält, können die Elemente der Auswahl Liste Aggregatfunktionen sein, GROUP BY-Ausdrücke, Konstanten oder Ausdrücke eines davon beinhaltet.

Von PostgreSQL docs

Wenn GROUP BY vorhanden ist, oder irgendwelche Aggregatfunktionen sind vorhanden, es ist nicht gültig für die SELECT-Liste Ausdrücke ungruppierten Spalten außer in Aggregatfunktionen beziehen sich auf oder wenn die Die nicht gruppierte Spalte ist funktional von den gruppierten Spalten abhängig, da andernfalls mehr als ein möglicher Wert für eine nicht gruppierte -Spalte zurückgegeben würde. Eine funktionale Abhängigkeit besteht, wenn die gruppierten Spalten (oder eine Teilmenge davon) der Primärschlüssel der Tabelle sind, die die nicht gruppierte Spalte enthält.

Verwandte Themen