2014-12-31 9 views
6

Si tratta di un'entità del campione:JPA gruppo di query Criteri per usi solo l'ID

public class Account{ 

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

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

Ora ho creare una query criteri con Partecipa come 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(); 

Il codice di cui sopra generano comandi Sql come seguente:

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

Sopra lavoro codice PosgreSQL ma non può essere eseguito in Oracle, perché in esso selezionare accType.name che doesn apparire nel gruppo per clausola

aggiornamento:
Penso che la mia domanda non è chiaro per voi. La mia domanda non riguarda il comportamento di PostgreSQL o Oracle in group by. La mia domanda è questa:
Io uso typeJoin nella clausola group by (ciò significa che mi aspetto di utilizzare il campo Hibernate tutti i campi di AccountType in group by), ma perché l'ibernazione usa solo il campo identità su group by? se userò solo campo di identità in group by allora posso utilizzare la seguente istruzione:

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

risposta

6

JPA/Hibernate non include automaticamente tutte le proprietà di entità di un gruppo dalla clausola, in modo da avere a loro specificare manualmente:

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

questa non è una buona idea. In questa soluzione ogni volta che AccountType cambia, la maggior parte cambia tutte le mie query. certo che posso gestirlo con la riflessione, ma penso che debba esserci una soluzione migliore per questo. sei sicuro che ibernare non includa tutte le proprietà di accesso? –

+0

È sufficiente specificare accountType.id e utilizzare una cache di secondo livello per caricarla successivamente. –

+0

Naturalmente, è possibile utilizzare anche il Metamodel JPA per recuperare tutti gli attributi del tipo di entità e inserirli nel gruppo in base al quale sarebbe generico. –

3

Se si utilizza GROUP BY, Oracle richiede che ogni colonna nell'elenco di selezione sia in GROUP BY.
PostgreSQL è lo stesso, tranne quando si raggruppa con la chiave primaria, quindi consente di selezionare qualsiasi colonna.

Da Oracle docs

In una query contenente una clausola GROUP BY, gli elementi di selezione elenco possono essere funzioni aggregate, GROUP BY espressioni, costanti o espressioni che uno di questi.

Da PostgreSQL docs

Quando GROUP BY è presente, o qualsiasi funzioni di aggregazione sono presenti, non è valido per la lista espressioni SELECT per fare riferimento a non raggruppati colonne se non nei funzioni di aggregazione o quando il la colonna non raggruppata dipende funzionalmente dalle colonne raggruppate, poiché altrimenti potrebbe essere più di un valore possibile da restituire per una colonna non raggruppata . Esiste una dipendenza funzionale se le colonne raggruppate (o un sottoinsieme) sono la chiave primaria della tabella contenente la colonna non raggruppata .

Problemi correlati