2013-06-11 5 views
5

che sto cercando di realizzare qualcosa di simile a quanto segue, utilizzando l'APP Criteri API:Come fare riferimento ad un campo specifico di sottoclasse in una CriteriaQuery in cui viene interrogata la super classe?

SELECT b FROM Box b JOIN SpecialItem s WHERE s.specialAttr = :specialAttr 

Gli oggetti sono

Box

@Entity 
public class Box implements Serializable { 
    ... 
    @ManyToOne 
    @JoinColumn(name = "item_id") 
    Item item; 
    ... 
} 

Articolo

@Entity 
@Inheritance(strategy = InheritanceType.JOINED) 
public class Item implements Serializable { 
    @Id 
    private String id; 
    ... 
} 

SpecialItem

@Entity 
public class SpecialItem extends Item { 
    private String specialAttr; 
    ... 
} 

Il mio tentativo

EntityManager em = getEntityManager(); 
CriteriaBuilder cb = em.getCriteriaBuilder(); 
CriteriaQuery cq = cb.createQuery(Box.class); 
Root from = cq.from(Box.class); 

// Nothing to specify SpecialItem over Item!  
Join join = from.join("item", JoinType.LEFT); 

// java.lang.IllegalArgumentException: Unable to 
// resolve attribute [specialAttr] against path [null]  
Path p = join.get("specialAttr"); 

Predicate predicate = cb.equal(p, "specialValue"); 
cq.where(predicate); 

Non sorprende che viene generata un'eccezione perché specialAttr non è un membro della classe Item.

Come posso restituire tutti gli Box es che contengono uno SpecialItem, dove lo SpecialItem.specialAttr ha qualche valore?

risposta

10

Se si utilizza JPA 2.1 è possibile utilizzare

"SELECT b FROM Box b WHERE TREAT(b.item as SpecialItem).specialAttr = :specialAttr" 

o

CriteriaQuery<Box> q = cb.createQuery(Box.class); 
Root<Box> box= q.from(Box.class); 
Join<Box, Item > order = box.join("item"); 
q.where(cb.equal(cb.treat(order, SpecialItem.class).get("specialAttr"), 
    qb.parameter(String.class, "specialAttr"))); 
q.select(Box); 
+0

Grazie, ma come farei utilizzando l'API Criteri? – Alex

+3

Grazie mille! Fuori se interesse, è una soluzione possibile con JPA 2.0? – Alex

+0

Sì, ma in un modo approssimativo che potrebbe causare ulteriori join. Dovresti essere esplicito nei tuoi join e costruire la query al contrario. Qualcosa come "seleziona b da Box b, SpecialtyItem si dove b.item = si e si.specialAttr =: specialAttr" – Chris

3

Voglio solo di estendere la risposta di Chris per l'API Criteri con meta-modello generato.

CriteriaQuery<Box> q = cb.createQuery(Box.class); 
Root<Box> box= q.from(Box.class); 
Join<Box, Item> order = box.join(Box_.item); 
q.where(cb.equal(cb.treat(order, SpecialItem.class).get(SpecialItem_.specialAttr), "searchValue"); 
q.select(Box); 
+0

grazie! non era davvero ovviamente! – dikkini

Problemi correlati