2010-01-19 1 views
28

Sto usando Hibernate 3.1.1, in particolare, sto usando query HQL.Come eseguire una query non polimorfica HQL in Hibernate?

Secondo il documentation, le query di Hibernate sono polimorfici:

una query come: from Cat as cat restituisce le istanze non solo di Cat, ma anche delle sottoclassi come DomesticCat.

Come posso eseguire una query per le istanze di Cat, ma non di alcuna delle sue sottoclassi?

mi piacerebbe essere in grado di farlo senza dover menzionare in modo esplicito ogni sottoclasse.

Sono consapevole delle seguenti opzioni, e non li trovo soddisfacente:

  1. filtrare manualmente le istanze dopo che la query, OR:
  2. l'aggiunta manuale di una clausola WHERE sulla colonna discriminatore.

Avrebbe senso per Hibernate per consentire all'utente di decidere se una query dovrebbe essere polimorfico o no, ma non riesco a trovare una tale opzione.

Grazie in anticipo!

risposta

25

Usa polymorphism="explicit" nel class mapping. Ciò comporterà che le query restituiscano solo le istanze della classe denominata e non le sue sottoclassi.

polimorfismo implicito significa che istanze della classe saranno restituiti da una query che i nomi di eventuali superclasse o interfaccia implementata o di classe, e che le istanze di qualsiasi sottoclasse della classe verrà restituito da un query che denomina la classe . Il polimorfismo esplicito significa che le istanze di classe verranno restituite solo da query che nominano esplicitamente tale classe .

+1

+1 buona scoperta ... – skaffman

+3

Fantastico! Nel mio caso, ho bisogno che sia su base per-query, e non per entità, ma penso di vedere un modo per farlo - sovrascrivendo il metodo 'isExplicitPolymorphism' sul mio' EntityPersister'. Sicuramente mi hai dato una spinta nella giusta direzione. –

15
SELECT cat FROM Cat cat WHERE cat.class='cat' 

in cui il valore 'cat' è il valore discriminante della classe Cat.

Se si utilizza TABLE_PER_CLASS, quindi provare cat.class='Cat') (il nome della classe)

Questo non è esattamente una clausola where per la colonna discriminatore, perché una tale interrogazione fallirà (la colonna discriminatore è disponibile solo nelle query native).

+0

Grazie, ma sto cercando di evitare di modificare la clausola WHERE. Se seguo il tuo suggerimento, Hibernate aggiungerà la sua parte al WHERE e finirà per essere "WHERE c.class = 'cat' AND c.class IN ('cat', 'domesticCat')". Preferirei avere un modo per dire a una query di "disattivare" la sua capacità polimorfica per una volta (se esiste una cosa del genere). –

+0

perché non si desidera specificare la clausola where? – Bozho

+1

Becco un pezzo di codice framework generico che esegue query diverse su entità diverse. Mi piacerebbe essere in grado di passare un parametro di configurazione al codice generico, per passare dalla modalità polimorfica a quella non polimorfica. Il codice generico __will__ modifica la clausola where se necessario, ma ciò richiederebbe di cercare il valore del discriminatore (sebbene non sia difficile), e probabilmente determinerà parti non necessarie nella clausola where (vedi il mio commento precedente). –

1

L'ORM imita il modello Java: se un oggetto è un'istanza di un altro tipo (se un'istanza di PersianCat è anche un'istanza di Cat), qualsiasi query su Cat dovrà essere polimorfica (immagina di eseguire una query su un elenco e chiedendo se le voci corrispondono a instanceof Cat.

Anche la soluzione di Bozho è in qualche modo impura, poiché la colonna "classe" è presumibilmente opaca alla mappatura di ibernazione, anche se ammetto che è un ottimo compromesso. nome semplice

Se sei comodo e utilizza tabella per classe si può sempre fare una query nativo al tavolo Cat per ottenere gli ID e quindi ottenere le voci tramite Hibernate.

+1

Hai ragione, il 99% delle volte dovresti trattare un'istanza di una sottoclasse come qualsiasi altra istanza della classe base, proprio come l'uso di 'x instanceof Cat' in Java. La mia domanda, tuttavia, riguarda l'altro 1%, quando c'è un motivo per cui non vuoi caricare il sottotipo - proprio come usando 'x.getClass() == Cat.class' in Java. Nel mio caso, è durante il bootstrap di sistema, quando non riesco ancora a creare istanze di sottotipo. –

+1

Puoi condividere il tuo design? Normalmente quando le cose sono così difficili c'è un cambiamento nel design che può avere un difetto o un modo migliore di fare le cose. –

0

Vedere BaseQueryReturnFieldsCalculatorGC; aggiunge dinamicamente una condizione al "dove" che seleziona solo dove class = XXX; è possibile duplicare questa logica in HQLQueryTemplate e definire l'utente 'isNonPolymorphic'.

Si noti che funzionerà solo con la tabella per gerarchia, cos solo allora la colonna della classe implicita esiste ed è selezionabile.

+1

Bentornato! :-) –

11

JPA 2 (Hibernate 3.5) aggiunge il supporto per le query non polimorfiche, questo è molto simile alla proprietà Hibernates .class (come Bozho ha risposto sopra) ma non è specifico di Hibernate. Questo viene fatto usando l'operatore TYPE. Come in

Select b from Book b where TYPE(b) = Book 

Si può leggere di più su here nel mio blog

Eyal

+0

Recentemente ho aggiornato da Hibernate 4.1.3 a 4.3.5, richiesto per Java 8. La mia query non polimorfica è ora interrotta: l'SQL generato da Hibernate è semplicemente sbagliato. Nella 4.1.3 già stava facendo qualche interruttore/caso funky nella clausola where, ma ora è solo errato: il valore della colonna discriminatore (a String) è * non quotato *: "... nel caso in cui paziente0_1_ .id non è null allora A quando patient0_.id non è nullo quindi 'P' end <> 'A' ..." La mia classe di amputato estende Patient, con discriminatore paziente" P "e Amputato" A. "In" allora A ", trascura di citare l'A, generando quindi un codice SQL non valido. –

+1

Vedere la mia estensione a questo problema: http://stackoverflow.com/questions/24512975/non-polymorphic-queries-with-hibernate-jpa-jpql –

+1

può mancare l'operatore '=' Prova:. TIPO (b) = libro – GPrimola