2013-07-17 13 views
19

Ho una classe Cat e una classe Owner. Un gatto ha un proprietario ma un proprietario può avere molti gatti. Quello che voglio interrogare è "prendi tutti i proprietari che hanno il gatto con gli occhi azzurri".I criteri di ibernazione uniscono la query uno a molti

class Cat{ 
Owner owner; //referenced from Owner.id 
String eyeColor; 
} 

class Owner{ 
List<Cat> catList; 
} 

Ho provato alcuni codici ma davvero non so cosa fare.

Criteria criteria = getCurrentSession().createCriteria(cat.getClass(), "cat"); 
criteria.createAlias("cat.owner", "owner");  
criteria.add(Restrictions.eq("cat.eyeColor", "blue"); 
+1

L'associazione è bidirezionale? Perché non usare HQL per una query così statica? –

+0

@JBNizet scusa ma non ho scelta come usare HQL. – hellzone

+0

L'associazione è bidirezionale? Perché non hai la scelta? È come se un falegname non fosse autorizzato a usare un martello! –

risposta

34

I criteri possono selezionare solo le proiezioni o l'entità radice. Non qualche entità unita. Alcune query sono quindi impossibili da esprimere con Criteria (che è un altro buon motivo per usare HQL, oltre a una migliore leggibilità e concisione).

Qui non tutto è perduto, perché la tua associazione è bidirezionale. Quindi, è sufficiente l'equivalente della query HQL

select distinct owner from Owner owner 
join owner.cats cat 
where cat.eyeColor = 'blue' 

Qual è

Criteria c = session.createCriteria(Owner.class, "owner"); 
c.createAlias("owner.cats", "cat"); 
c.add(Restrictions.eq("cat.eyeColor", "blue"); 
c.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY); 
+0

Nel mio caso, il gatto conosce il proprietario, ma il proprietario non sa dei suoi gatti. Come apparirebbe il criterio? – Kayser

+0

Come detto nella mia risposta, AFAIK (a meno che non lo abbiano reso possibile nelle versioni più recenti), non è possibile utilizzare i criteri. Utilizzare HQL o utilizzare l'API dei criteri JPA2. –

+0

Operazione "distinta" in memoria. Se un proprietario ha un milione di gatti blu-eyed, li preleverà tutti dal database, solo per trovare il singolo proprietario (l'esempio non è probabilmente il caso reale degli utenti, non si conosce la reale cardinalità). Vedi la mia risposta come potrebbe essere fatto nel database. – Oliv

4

Prova questo:

DetachedCriteria dc = DetachedCriteria.forClass(Cat.class, "inner") 
    .add(Restrictions.eq("eyeColor", "blue")) 
    .add(Restrictions.eqProperty("inner.owner", "outer.pk")); 

session.createCriteria(Owner.class, "outer") 
    .add(Subqueries.exists(dc)) 
    .list(); 

Questo può utilizzare indice nel database e non farà un a -memoria distinct operazione come nella versione di @JB Nizet (vedere il mio commento lì). L'indice sarà:

CREATE INDEX idx_cat_owner_eyecolor ON Cat(fkOwner, eyeColor) 

Pensate distinct funzionamento (sia in SQL o in memoria) come un odore di codice. È usato raramente e molti programmatori alle prime armi lo usano per risolvere il problema "perché ho questa riga due volte". Può quasi sempre essere riscritto come in questo caso. I casi d'uso, quando è necessario, sono pochi.