2010-01-19 18 views
28

Estoy usando Hibernate 3.1.1 y, en particular, estoy usando consultas HQL.¿Cómo realizar una consulta HQL no polimórfica en Hibernate?

De acuerdo con la documentation, consultas de Hibernate son polimórficos:

una consulta como: from Cat as cat devuelve instancias no sólo de Cat, sino también de subclases como DomesticCat.

¿Cómo puedo consultar instancias de Cat, pero no de ninguna de sus subclases?

Me gustaría poder hacerlo sin tener que mencionar explícitamente cada subclase.

Soy consciente de las siguientes opciones, y no los encuentra satisfactoria:

  1. filtrado manual de los casos después de la consulta, O:
  2. Adición manual de una cláusula WHERE en la columna discriminadora.

Tendría sentido para Hibernate permitir al usuario decidir si una consulta debe ser polimórfica o no, pero no puedo encontrar tal opción.

¡Gracias de antemano!

Respuesta

25

Use polymorphism="explicit" en el class mapping. Esto hará que las consultas devuelvan solo instancias de la clase nombrada y no sus subclases.

polimorfismo implícito significa que instancias de la clase serán devueltos por una consulta que los nombres de cualquier superclase o interfaz implementada o clase, y que los casos de cualquier subclase de la clase será devuelto por una consulta que nombra la clase . Polimorfismo explícito significa que las instancias de clase se devolverán solo mediante consultas que explícitamente nombre esa clase.

+1

+1 buen descubrimiento ... – skaffman

+3

¡Increíble! En mi caso, necesito que esté en base a consultas, y no por entidad, pero creo que veo una manera de hacerlo, anulando el método 'isExplicitPolymorphism' en mi' EntityPersister'. Ciertamente me dieron un empujón en la dirección correcta. –

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

donde el valor 'cat' es el valor discriminador de la clase Cat.

Si está utilizando TABLE_PER_CLASS, a continuación, tratar cat.class='Cat') (el nombre de la clase)

Esto no es exactamente una cláusula where de la columna discriminadora, porque dicha consulta fallará (columna discriminadora es disponible solo en consultas nativas).

+0

Gracias, pero estoy tratando de evitar la edición de la cláusula WHERE. Si sigo su sugerencia, Hibernate agregará su propia porción al DONDE, y terminará siendo "DONDE c.class = 'cat' AND c.class IN ('cat', 'domesticCat')". Prefiero tener una manera de decirle a una consulta que "apague" su capacidad polimórfica por una vez (si tal cosa existe). –

+0

¿Por qué no desea especificar la cláusula where? – Bozho

+1

Porque tengo un código de marco genérico que ejecuta diferentes consultas en diferentes entidades. Me gustaría poder pasar un parámetro de configuración al código genérico para cambiar entre el modo polimórfico y el no polimórfico. El código genérico __will__ modificará la cláusula where si fuera necesario, pero eso requeriría buscar el valor discriminador (aunque no es difícil), y probablemente resultará en partes innecesarias en la cláusula where (ver mi comentario anterior). –

1

El ORM imita el Modelo Java: si un objeto es una instancia de otro tipo (si una instancia de PersianCat es también una instancia de Cat), cualquier consulta sobre Cat tendrá que ser polimórfica (imagine que consulta una Lista y preguntando si las entradas coinciden con instanceof Cat.

Incluso la solución de Bozho es algo impura, ya que la columna 'clase' es supuestamente opaca a su mapeo de hibernación, aunque admito que es un muy buen compromiso. Simplemente puede obtener el discriminador a través del classe nombre simple.

Si está cómodo y están usando la tabla por clase siempre puede hacer una consulta nativa a la tabla Cat para obtener los ID y luego obtener las entradas a través de Hibernate.

+1

Tienes razón, el 99% del tiempo debes tratar una instancia de una subclase como cualquier otra instancia de la clase base, como usar 'x instanceof Cat' en Java. Mi pregunta, sin embargo, es sobre el otro 1%, cuando hay una razón por la que no desea cargar el subtipo, como usar 'x.getClass() == Cat.class' en Java. En mi caso, es durante el arranque del sistema, cuando todavía no puedo instanciar objetos de subtipo. –

+1

¿Puedes compartir tu diseño? Normalmente cuando las cosas son tan difíciles, hay un cambio en el diseño que puede tener un defecto o una mejor manera de hacer las cosas. –

0

Mire BaseQueryReturnFieldsCalculatorGC; agrega dinámicamente una condición al 'dónde' que selecciona solo donde clase = XXX; puede duplicar esta lógica en HQLQueryTemplate y hacer que el usuario defina 'isNonPolymorphic'.

Tenga en cuenta que solo funcionará con tabla por jerarquía, porque solo entonces existe la columna de clase implícita y es seleccionable.

+1

¡Bienvenido de nuevo! :-) –

11

JPA 2 (Hibernate 3.5) agrega soporte para consultas no polimórficas, esto es muy similar a la propiedad .class de Hibernate (como Bozho respondió anteriormente) pero no es específica de Hibernate. Esto se hace usando el operador TYPE. Al igual que en

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

Puede leer más sobre here en mi blog

Eyal

+0

Recientemente me actualicé de Hibernate 4.1.3 a 4.3.5, requerido para Java 8. Mi consulta no polimórfica ahora está rota: el SQL que genera Hibernate, es simplemente incorrecto. En 4.1.3 ya estaba haciendo un funky switch/case en la cláusula where, pero ahora es simplemente incorrecto: el valor de la columna del discriminador (a String) * no está citado *: "... where case when patient0_1_ .id no es nulo, entonces A cuando patient0_.id no es nulo, entonces 'P' end <> 'A' ..." Mi clase Amputee extiende Patient, con el discriminador de pacientes 'P' y Amputee 'A'. En" then A ", omite citar el A, generando SQL no válido. –

+1

Ver mi extensión a este problema: http://stackoverflow.com/questions/24512975/non-polymorphic-queries-with-hibernate-jpa-jpql –

+1

Puede faltar el operador '='. Prueba: TYPE (b) = Book – GPrimola

Cuestiones relacionadas