2010-08-02 8 views
5

Tengo una aplicación que usa Hibernate para la persistencia de datos, con Spring en la parte superior (para una buena medida). Hasta hace poco, había una clase persistente en la aplicación, A:¿Es una mala práctica usar DiscriminatorFormula para migrar las bases de datos de Hibernate?

@Entity 
public class A { 
    @Id 
    @Column(unique = true, nullable = false, updatable = false) 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    private long id; 
    public String name; 
} 

Desde entonces he añadido una subclase de A, llamado B:

@Entity 
public class B extends A { 
    public String description; 
} 

Después de la adición de B, ahora podría no cargar una de . La siguiente excepción fue arrojado:

class org.springframework.orm.hibernate3.HibernateObjectRetrievalFailureException :: Object with id: 1 was not of the specified subclass: A (Discriminator: null); nested exception is org.hibernate.WrongClassException: Object with id: 1 was not of the specified subclass: A (Discriminator: null) 

que añade la siguiente anotación y la propiedad de B, y parece haber resuelto el problema. ¿Es esta la manera correcta de resolver el problema?

... 
@DiscriminatorFormula("(CASE WHEN dtype IS NULL THEN 'A' ELSE dtype END)") 
public class A { 
    private String dtype = this.getClass().getSimpleName(); 
    ... 

Respuesta

2

(...) Hasta hace poco, había una clase persistente en la aplicación, A:

Con la siguiente representación de base de datos:

ID NAME 
-- ---- 
1 foo 
2 bar 

I desde entonces se ha agregado una subclase de A, llamada B (...)

Y no especificó la anotación Inheritance por lo que se utiliza la estrategia de asignación SINGLE_TABLE. Y En esta estrategia, todas las clases en una jerarquía están mapeadas en una sola tabla. La tabla tiene una columna que sirve como una "columna discriminatoria", es decir, una columna cuyo valor identifica la subclase específica a la que pertenece la instancia representada por la fila.

La tabla a continuación, se convirtió en:

ID NAME DTYPE 
-- ---- ----- 
1 foo NULL 
2 bar NULL 

Dónde DTYPE es el nombre predeterminado de la columna que se utilizará para el discriminador.

Después de agregar B, ahora no podría cargar A's. Se arrojó la siguiente excepción (...)

De hecho, como los valores existentes tienen un valor nulo en la columna del discriminador, el proveedor no sabe qué subclase crear.

He añadido la siguiente anotación y propiedad a B, y parece que he resuelto el problema. ¿Es esta la manera correcta de resolver el problema?

Eso es de una manera, pero es intrusivo (sus entidades no deben conocer la columna dtype) e Hibernate específico. En otras palabras, es un truco.

Para mí, la forma "correcta" de resolver esto sería para actualizar la columna DTYPE de un registros existentes para establecer el valor de 'A' (con Hibernate, toma el valor predeterminado para el nombre de la entidad):

UPDATE A SET DTYPE='A' WHERE DTYPE=NULL 

De esta forma, Hibernate podría cargarlos correctamente.

+0

gracias por la respuesta detallada. Lamentablemente, no tendré acceso directo a todas las instalaciones de la aplicación, por lo que me gustaría que este cambio de esquema se realice de forma transparente a los usuarios. Intenté agregar DiscriminatorFormula sin definir explícitamente el campo dtype, pero esto no funcionó. Se sentía como un truco cuando lo estaba haciendo - es por eso que pregunté. – Armand

+1

@Alison De nada. Te di lo que es IMO la solución "ideal". Si no es adecuado en su contexto, si no puede proporcionar una secuencia de comandos de migración a sus usuarios (que realizaría el 'ACTUALIZACIÓN' después de varios 'ALTER') - o incluso mejor una herramienta de migración automatizada - entonces su solución es aceptable. Al menos funciona Y ahora sabes que es un hack :) –

+0

-) He encontrado información sobre migraciones en Hibernate/Spring bastante difícil de conseguir, desafortunadamente. – Armand

Cuestiones relacionadas