2013-08-16 8 views
11

ho un criterio che restituisce tutti i dati l'applicazione richiede, in sostanza:Hibernate Criteri: entità distinte e quindi limitare

Criteria criteria = session.createCriteria(Client.class); 
criteria.createAlias("address", "address"); 
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); 
criteria.setFirstResult(init); 
criteria.setMaxResults(max); 
List<Client> clients = criteria.list(); 

Il problema è che il cliente relazione/indirizzo è bidirezionale: il cliente ha un indirizzo e un indirizzo può appartenere a più di un cliente.

Desidero recuperare gli oggetti client "singoli" in base al loro pk, ovviamente, un certo numero di client come vengono visualizzati in una tabella.

Poiché vengono impostati innanzitutto setFirstResult/setMaxResults, ricevo client duplicati entro i limiti già applicati. Dopo (è stato utilizzato il livello applicazione come non gruppo da), l'ibernazione si libera dei client duplicati, quindi finisco con meno client rispetto al massimo specificato in setMaxResults.

Impossibile raggruppare per (gruppo di proiezione) poiché non restituirà tutte le colonne richieste in client/indirizzi, solo il gruppo per cui la query è raggruppata.

(Per riassumere, La mia tabella ha 100 risultati per pagina ma dopo aver scartato i duplicati ho 98 risultati anziché 100 ...) perché il limite: LIMIT 0,100 viene applicato PRIMA dei gruppi di ibernazione quando deve essere eseguito DOPO)

risposta

7

Come si evidenzia nel thread collegati da riga successiva "Ashish Thukral" risolve questo:

criteria.setFetchMode("address.clients", FetchMode.SELECT); 

impedisce il join che causa il problema da effettuare.

Ovviamente, è possibile rimuovere fetch = "join" dal file di configurazione xml ma questa soluzione non influisce su altri punti in cui è possibile che i bean vengano recuperati.

+0

FetchMode.SELECT l'ha corretto per me: le altre modalità non funzionano in questo caso. –

+0

FetchMode.SELECT è eccezionale ... tranne per il fatto che impone un recupero ansioso, per qualche motivo. Vedi https://docs.jboss.org/hibernate/core/3.3/api/org/hibernate/FetchMode.html Non c'è modo di dire in ibernazione semplicemente di fare un "distinto" sul pk dell'entità che viene recuperata ?? Questa sembra la cosa più ovvia e banale da volere e, come al solito, l'ibernazione rende la vita estremamente complicata per noi. – Marc

+0

A proposito, fare questo con HQL è banale quanto sembra. Basta aggiungere la parola "distinta" nella query. Perché questo è così dolorosamente oneroso usando l'API Criteri è oltre me. Possiamo iniziare a utilizzare i database OO? – Marc

4

Se si cerca Client in base all'id come segue. In base ai tuoi criteri, non è necessario specificare la dimensione max e init perché restituisce sempre un client.

Criteria criteria = getSession().createCriteria(Client.class); 
criteria .add(Restrictions.eq("id", yourClientId); 
criteria.createAlias("address", "address"); 
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); 
criteria.setFirstResult(init); 
criteria.setMaxResults(max); 
List<Client> clients = criteria.list(); 

Se si cerca Indirizzo in base all'id come segue.

Criteria criteria = getSession().createCriteria(Client.class); 
criteria.createAlias("address", "address"); 
criteria .add(Restrictions.eq("address.id", yourAddressId); 
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); 
criteria.setFirstResult(init); 
criteria.setMaxResults(max); 
List<Client> clients = criteria.list(); 
+3

grazie mille per la risposta, ma cercavo tutti i client, restituendoli come risposta nelle pagine. Il problema è che una pagina che dovrebbe restituire 100 risultati, restituisce meno dopo averli raggruppati (DISTINCT_ROOT_ENTITY). Quel raggruppamento dovrebbe accadere prima del limite ... – kandan

+0

il secondo blocco potrebbe risultare in un numero minore di righe come postato da @kandan nella sua domanda –

0

Se ho capito bene le vostre relazioni, si avrà un elenco di cliente in indirizzo e Un indirizzo in ogni classe entità cliente. Quindi, se volete solo un elenco di clienti, qual è il grosso problema, non puoi semplicemente tirare

Criteria criteria = session.createCriteria(Client.class); 
criteria.setFirstResult(init); 
criteria.setMaxResults(max); 
List<Client> clients = criteria.list(); 

Perché stai creando un alias e utilizzando distinct_root_entity? Se hai bisogno di ottenere quell'indirizzo, quando accedi a DAO o ServiceImpl, Hibernate comunque lo preleva pigramente per te.

Correggimi se sbaglio.

+0

Grazie. Sto creando un alias per forzare l'ibernazione ad ottenere altri dati nella query, poiché potrei filtrare i client, ad esempio il loro codice postale (è una tabella impaginata con filtri). Quindi ottengo tutti i dati di cui ho bisogno: i clienti con indirizzo.il problema è che con l'indirizzo arriva anche un insieme di client che hanno quell'indirizzo e ho bisogno di unformatore di risultati per unificare i client con il loro id. Probabilmente è possibile, senza modificare alcuna annotazione, dire di ibernare non recuperare/unire una colonna specifica per una classe/tabella, ma farlo negli altri campi, qualunque sia il predefinito definito (pigro o meno) specificato. – kandan

+1

penso che stiate cercando questo http://stackoverflow.com/questions/5567754/hibernate-criteria-n1-issue-with-maxresults?rq=1 –

+0

sì, grazie per quello. – kandan