2012-08-30 19 views

Respuesta

8

Como estoy repasando esto una y otra vez, creo que podría ayudar a aclarar: En primer lugar, es cierto que Hibernate no requiere discriminación cuando se usa el mapeo JOINED_TABLE. Sin embargo, sí lo requiere cuando usa SINGLE_TABLE. Aún más importante, otros proveedores de JPA generalmente lo requieren.

Lo Hibernate realmente hace cuando se realiza una JOINED_TABLE consulta polimórfica es crear un discriminador llamado clazz sobre la marcha, usando un caso-interruptor que comprueba la presencia de campos únicos para las subclases concretas tras exterior de unión de todas las tablas que participan en el árbol de herencia. Puede ver esto claramente cuando se incluye la propiedad "hibernate.show_sql" en su persistence.xml. En mi opinión, esta es probablemente la solución perfecta para las consultas JOINED_TABLE, por lo que la gente de Hibernate está en lo cierto al jactarse de ello.

El asunto es algo diferente cuando se realizan actualizaciones y eliminaciones; aquí hibernate primero consulta su tabla de raíz para cualquier clave que coincida con la cláusula where de la declaración, y crea un pkTable virtual a partir del resultado. Luego realiza un "DELETE FROM/UPDATE table WHERE pk IN pkTable" para cualquier clase concreta con su árbol de herencia; el operador IN causa que se escanee una subconsulta de O(log(N)) por entrada de tabla, pero es probable que esté en la memoria, por lo que no está nada mal desde el punto de vista del rendimiento.

Para responder a su pregunta específica, Hibernate simplemente no ve un problema aquí, y desde cierta perspectiva están en lo cierto. Sería increíblemente fácil para ellos simplemente cumplir con las anotaciones @DiscriminatorValue al inyectar los valores del discriminador durante entityManager.persist(), incluso si no los usan realmente. Sin embargo, no respetar la columna del discriminador en JOINED_TABLE tiene la ventaja (para Hibernate) de crear un caso leve de lockin del vendedor, e incluso es defendible apuntando a una tecnología superior.

@ForceDiscriminator o @DiscriminatorOptions(force=true) ayudan a mitigar un poco el dolor, pero tiene que usarlos antes de que se creen las primeras entidades, o verse obligado a agregar manualmente los valores del discriminador faltantes mediante sentencias de SQL. Si te atreves a alejarte de Hibernate, al menos te costará cambiar el código para eliminar estas anotaciones específicas de Hibernate, creando resistencia contra la migración. Y eso es obviamente todo lo que le importa a Hibernate en este caso.

En mi experiencia, el vendedor lockin es el paraíso de los sueños más salvajes de todo líder de mercado, porque es la varita mágica maquiavélica que protege la participación en el mercado sin esfuerzo; por lo tanto, se realiza cuando los clientes no se defienden y le imponen un precio superior al de los beneficios obtenidos. ¿Quién dijo que un mundo de código abierto sería diferente?

p.s, solo para evitar confusiones: de ninguna manera estoy afiliado a ningún implementador de JPA.

p.p.s: Lo que suelo hacer es ignorar el problema hasta el momento de la migración; a continuación, puede formular una declaración SQL UPDATE ... FROM utilizando el mismo truco case-switch-with-outer-joins que Hibernate utiliza para completar los valores del discriminador faltantes. En realidad es bastante fácil una vez que has entendido el principio básico.

2

Creo que esto es más de mi opinión, pero creo que algunos estarán de acuerdo conmigo. Prefiero el hecho de que Hibernate te permite no usar un discriminador. En varios casos, el discriminador no es necesario.

Por ejemplo, tengo una entidad Person que contiene cosas como un nombre, una fecha de nacimiento, etc. Esta entidad puede ser utilizado por varias otras entidades como Employee o Customer. Cuando no hago referencia a Person desde otras entidades, sino que hago referencia a Employee o Customer, el discriminador no se utiliza ya que se ordena a Hibernate buscar uno.

+0

Buen punto, pero aún hay casos en hibernación no va a funcionar (WrongClassException). ¿Por qué Hibernate no funciona de la caja sin forzar? – yannisf

+0

@yannisf Creo que eso depende de su código/diseño. He usado Hibernate varias veces sin discriminadores y nunca tuve este problema. – siebz0r

3

Chicos, permítanme explicar sobre @DiscriminatorOptions(Force=true). Bueno, se usa en heredadera de tabla única, lo he usado recientemente en uno de los escenarios. tengo dos entidades que se asignaron a una sola tabla. cuando estaba tratando de obtener el registro de una entidad, estaba obteniendo una lista de registros contables de resultados de ambas entidades y este era mi problema. Para resolver este problema he usado @DiscriminatorOptions(Force=true) que creará el predicado usando la columna Discriminador con el valor especificado mapeado a la entidad correspondiente. por lo que la consulta se parecen a esto después de que solía @DiscriminatorOptions(Force=true)

select * 
from TABLE 
where YOUR PREDICATE AND DiscriminatorColumn = DiscriminatorValue 
-1

@yannisf ForceDiscriminator no es la única solución para resolver este problema.

Puede hacer una instancia de pruebas para cada clase secundaria. Aunque esto será como codificar las clases en el código, pero es una manera más limpia de resolver el problema si la columna del discriminador no está llena.

Esto también ayuda a su código a evitar la mezcla de jpa e hibernación de anotaciones.

Como lo señaló yannisf, instanceOf es una especie de antipatrón en el mundo de OO.

Otra solución podría ser cambiar la asignación de su entidad. Supongamos que una entidad A tiene una referencia a una superclase B y B tiene clases secundarias de tipo C1 y C2, en lugar de A apuntando a B, puede tener C1 y C2 con una clave externa que apunta a A. Todo se reduce a cambiar el diseño de la entidad para no mezclar anotaciones.

Gracias Vaibhav

+0

Gracias por tu comentario. instanceOf con respecto a los proxies dinámicos (ver la carga diferida) ha demostrado ser una herramienta muy poco confiable. Además, instanceOf es un antipatrón de diseño en el mundo OO. Finalmente, uno debería codificar la lógica arbitraria para decidir sobre la resolución de clase real. – yannisf