2013-04-13 20 views
13

Voglio fare una query in cui mi unisco a 2 tabelle, utilizzando il CriteriaBuilder. In MySQL query sto cercando di fare sarebbe simile a questa:Come far aderire un CriteriaBuilder con una condizione "attiva" personalizzata?

SELECT * FROM order 
LEFT JOIN item 
ON order.id = item.order_id 
AND item.type_id = 1 

voglio ottenere tutti gli ordini e se hanno un elemento di tipo # 1, voglio unirmi a questa voce. Tuttavia, se non viene trovato alcun elemento del tipo # 1, desidero comunque ottenere l'ordine. Non riesco a capire come farlo con il CriteriaBuilder. Tutto quello che so come fare è:

CriteriaBuilder cb = em.getCriteriaBuilder(); 
CriteriaQuery<Order> cq = cb.createQuery(Order.class); 
Root<Order> order = cq.from(Order.class); 
Join<Order, Item> item = order.join(Order_.itemList, JoinType.LEFT); 
Join<Item, Type> type = order.join(Item_.type, JoinType.LEFT); 
cq.select(order); 
cq.where(cb.equal(type.get(Type_.id), 1)); 

Questa query è rotto, in quanto si traduce in qualcosa di simile in MySQL:

SELECT * FROM order 
LEFT JOIN item 
ON order.id = item.order_id 
WHERE item.type_id = 1 

Il risultato conterrà solo ordini con elementi di tipo # 1. Gli ordini senza sono esclusi. Come posso utilizzare CriteriaBuilder per creare una query come nel primo esempio?

+0

_Voglio ricevere tutti gli ordini e se hanno un articolo di tipo # 1, questo elemento deve essere incluso in result_ Che tipo di risultato vuoi? Ordine? O una tupla/multiselect? Cosa vuoi di più di tutti gli ordini? Spiega – perissf

+0

Scusa, non ero molto chiaro. Ho corretto la descrizione. Non sono realmente interessato a ottenere l'oggetto come parte del mio risultato. Voglio solo ordini nel mio risultato. Fondamentalmente, voglio ordinare il risultato sulla base di elementi di un tipo specifico, mentre ricevo ancora ordini senza quel tipo di elementi. –

+0

È possibile con CriteriaBuilder! Guarda la mia risposta qui sotto – Mitchapp

risposta

1

Penso che questo sia lo stesso problema posto in questa domanda. Sembra che non sia possibile in CriteriaBuilder. È possibile in Hibernate Criteria API, ma probabilmente non ti aiuterà.

JPA Criteria API: Multiple condition on LEFT JOIN

+0

Il primo MySQL è ciò che voglio che il mio CriteriaBuilder generi. Il secondo MySQL rappresenta ciò che genera la CriteriaQuery mostrata. Se aggiungo semplicemente "o item.id è null" alla seconda query MySQL, non otterrò quello che voglio. In questo modo si escludono gli ordini con articoli che hanno un id type diverso da 1 e restituiscono solo gli ordini con elementi di tipo 1 o nessun elemento. –

+0

L'ho capito ora. Bjørn. Sto modificando la mia risposta. – carbontax

+0

Grazie. Potrei fare un tentativo su una scala più piccola, ma sul mio progetto attuale probabilmente non mi aiuterà. In questo momento sono su EclipseLink (JPA 2.0). Per quanto ho potuto scoprire ([link] (https://blogs.oracle.com/arungupta/entry/jpa_2_1_early_draft), la funzione di cui ho bisogno non sarà disponibile fino al JPA 2.1. Spero che lo farà presto. –

0

So che questa domanda è stata fatta molto tempo un andare, ma di recente una ha avuto lo stesso problema e ho trovato questa soluzione da un forum di Oracle, ho copiato e incollato nel caso in cui il collegamento non è più lungo a disposizione.

MiguelChillitupaArmijos 29-apr-2011 01:41 (it respuesta a 840.578) Think si dovrebbe usare qualcosa come:

em.createQuery("SELECT DISTINCT e.Id" + 
        " from Email e " + 
        " left join e.idEmailIn e2 *with* e2.responseType = 'response'" + 
        "  where e.type = 'in' and e.responseMandatory = true").getSingleResult(); 

Un questo è il link.

JPA Criteria : LEFT JOIN with an AND condition

-1

c'è una soluzione se si utilizza Hibernate 3.6 con JPA 2.0 Non è la soluzione migliore, ma funziona perfetto per me.

Ho duplicato l'entità con l'annotazione di ibernazione @Where. Significa che ogni volta che si utilizza il join con questa entità, la sospensione aggiungerà la condizione aggiuntiva nell'istruzione join all'SQL generato.

Per esempio, inizialmente abbiamo l'esempio seguente:

@Entity 
@Table(name = "PERSON") 
public class Person { 

    @Id 
    @Column(name = "PERSON_ID") 
    private Long id; 

    @Id 
    @Column(name = "PERSON_NAME") 
    private String name; 

    @OneToMany(mappedBy = "person", fetch = FetchType.LAZY) 
    private Set<Address> addresses; 

} 

@Entity 
@Table(name = "ADDRESS") 
public class Address { 

    @Id 
    @Column(name = "ADDRESS_ID") 
    private Long id; 

    @Id 
    @Column(name = "ADDRESS_STREET") 
    private String street; 

    @ManyToOne 
    @JoinColumn(name = "PERSON_ID") 
    private Person person; 

} 

Per aggiungere condizioni in più su criteri di join, abbiamo bisogno di duplicare la mappatura Indirizzo @Entity, aggiungendo il @Where annotazioni @Where (clausola = "ADDRESS_TYPE_ID = 2").

@Entity 
@Table(name = "ADDRESS") 
@Where(clause = " ADDRESS_TYPE_ID = 2") 
public class ShippingAddress { 

    @Id 
    @Column(name = "ADDRESS_ID") 
    private Long id; 

    @Id 
    @Column(name = "ADDRESS_STREET") 
    private String street; 

    @OneToOne 
    @JoinColumn(name = "PERSON_ID") 
    private Person person; 

} 

Inoltre, è necessario aggiungere l'associazione di associazione duplicata per la nuova entità.

@Entity 
@Table(name = "PERSON") 
public class Person { 

    @Id 
    @Column(name = "PERSON_ID") 
    private Long id; 

    @Id 
    @Column(name = "PERSON_NAME") 
    private String name; 

    @OneToMany(mappedBy = "person", fetch = FetchType.LAZY) 
    private Set<Address> addresses; 

    @OneToOne(mappedBy = "person") 
    private ShippingAddress shippingAddress; 

} 

Infine, è possibile utilizzare un join con questo specifico Entity nei vostri criteri:

PersonRoot.join(Person_.shippingAddress, JoinType.LEFT); 

Il Hibernate frammento SQL dovrebbe Sembra che questo:

left outer join 
     address shippingadd13_ 
      on person11_.person_id=shippingadd13_.person_id 
      and (
       shippingadd13_.ADDRESS_TYPE_ID = 2 
      ) 
4

È CAN fare quello usando il metodo onJoin<Z, X> on(Predicate... restrictions);.

Ecco un esempio di lavoro:

... 
Root<Order> order = cq.from(Order.class); 
Join<Order, Item> item = order.join(Order_.itemList, JoinType.LEFT); 
item.on(cb.equal(item.get(Item_.type), 1)); 
... 
+0

Se funziona, ci saranno alcune query native che possono essere sostituite. Lo provo la prossima volta che ho bisogno di un join. –

+0

Non ho capito cosa intendi per "poche query native che possono essere sostituite"! Provalo prima e vedrai che funziona perfettamente! – Mitchapp

+0

Volevo solo dire che ho un sacco di posti dove uso 'entityManager.createNativeQuery (String)' a causa delle carenze del CriteriaBuilder. :-) –

0

clausola ON è supportata in Hibernate 4.3 versione, qualcuno è a conoscenza se v'è un problema di parametro di indicizzazione tra l'indice dei parametri delle condizioni personalizzate aggiuntive con l'indice del filtri di mappatura esistenti quando si esegue un join esterno con la clausola ON?

Utilizzando la classe di entità Persona di seguito come esempio, ad esempio sto aggiungendo questo filtro per limitare i tipi di indirizzo e il filtro è abilitato per popolare la clausola IN. L'indice dei parametri per la clausola IN causerà il problema [2] quando aggiungo condizioni aggiuntive (come l'utilizzo della colonna 'street') parte della clausola ON. È un problema noto?

[1] @Filter (name = "AddressTypes", condizione = "address_type in (: supportedTypes)")

[2] causato da: ERRORE 22018: formato stringa di caratteri valida per il tipo BIGINT. indirizzi Set privato;

Problemi correlati