2012-04-15 10 views
6

Estoy perdido aquí, y tal vez es algo obvio porque mi experiencia en Hibernate es más débil que en otras áreas.Hibernate cambiar clase incrustable para migrar datos existentes

En el código heredado hay una clase @Entity de Hibernate Foo. Uno de los sus propiedades es la siguiente:

private OldBar bar = new OldBar(); 

OldBar es una clase @Embeddable que utiliza una sola columna, foobar:

@Embeddable 
public class OldBar { 

    private String fooBar; 

    @Column(length = 10, nullable = false) 
    private String getFooBar() { 
    return fooBar; 
    } 

    @SuppressWarnings("unused") 
    private void setFooBar(String fooBar) { 
    this.fooBar = fooBar; 
    } 
} 

El problema original es que tenía que hacer algo con OldBar.fooBar, pero el el diseño original tenía limitaciones y tenía este campo privado, lo que me impedía crear subclases, así que tuve que crear una clase entera diferente, NewBar, para reemplazar a la otra y obtener acceso al campo privado. Pensé que desde NewBar es también Embeddable y tiene la misma designación @Column, que sólo podía intercambiar el campo de la clase Foo:

private NewBar bar = new NewBar(); 

que quería hacer esto porque tengo los datos existentes en la columna de la foobar, y Quería usar esta información de manera transparente con NewBar en lugar de OldBar.

A través de registros de seguimiento que he visto que Foo() se crea, con su versión predeterminada de NewBar(), como uno esperaría, cuando se llama al constructor. Sin embargo, por el código de tiempo llama a Foo.getBar(), por alguna razón bar es null! Supongo que Hibernate lo está configurando en null por alguna razón, pero ¿por qué Hibernate no lee los datos de la columna foobar y crea una instancia de NewBar? ¿Por qué funciona de nuevo cuando pongo OldBar en lugar de NewBar? Seguramente no hay nada en la base de datos que indique cuál de las clases @Embeddable está asignada a la columna, ¿verdad?

Actualización: Esto se vuelve más y más extraño. A veces voy a dejar el código de la noche a la mañana, ¡y al día siguiente funciona! ¡O al día siguiente no funciona! Justo ahora no funcionó (es decir, la propiedad foobar se estableció en null en lugar del valor en la base de datos), así que hice la clase ExactCopyOfOldBar y la puse en el lugar de OldBar. ¡Funcionó bien! Así que vuelvo a NewBar --- simplemente deshaciendo mis cambios temporales. ¡Todavía funcionaba, cuando no lo había hecho antes! ¿Hay algún tipo de caché donde Hibernate serialice los valores y no los obtenga de la base de datos? Esto es muy extraño.

Actualización: Ahora ya no puedo obtener NewBar para funcionar. Creo OtherBar, que es básicamente idéntico a NewBar excepto que tiene un nombre diferente, y lo enchufo y funciona, leyendo correctamente la cadena incrustada. Vuelvo a NewBar, y obtengo null nuevamente. Que esta pasando?

Nota que Foo se carga a través de net.databinder.auth.hib.AuthDataApplication.getUser(String username), que es bastante simple:

return (DataUser) Databinder.getHibernateSession().createCriteria(getUserClass()) 
    .add(Restrictions.eq("username", username)).uniqueResult(); 

He verificada una y otra vez que el (usuario) tabla Foo tiene una sola fila con los datos correctos, y lo más importante es que el campo foobar tiene datos. ¿Por qué Hibernate me devuelve un Foo con un campo nullfoobar? ¿Por qué simplemente cambiar de NewBar a OtherBar hace que comience a funcionar de nuevo? ¿Por qué funciona todo el día y luego deja de funcionar después de haberlo dejado durante la noche?

+0

Supongo que esto es cierto, pero usted no lo dijo: ¿'Foo.bar' está marcado como' @ Embedded'? –

+0

@Tim Pote: De hecho, curiosamente, en el código heredado original (en funcionamiento), _no se marcó como '@ Embedded'. Lo intenté con y sin '@ Embedded' cuando cambié de' OldBar' a 'NewBar', y no hizo la diferencia. –

+0

@Tim Pote: He aprendido de Hibernate [documentación] (http://docs.jboss.org/hibernate/annotations/3.5/reference/en/html_single/) que "... si el tipo de propiedad está anotado como @Embeddable, está mapeado como @ Embedded, "por lo que técnicamente la parte' @ Embedded' es opcional. –

Respuesta

1

Esta puede ser la respuesta; Tendré que esperar varios días para ver si realmente soluciona el problema. En realidad, hay dos partes.

En primer lugar, para la divulgación completa, mi clase NewBar era en realidad una subclase de AbstractBar. Eventualmente quería tener diferentes tipos de barras incrustables, así que coloqué @Embeddable en el nivel AbstractBar, no en el nivel NewBar, y coloqué el campo privado foobar en el nivel AbstractBar también. Lo curioso es que esto funcionó algunas veces. Y como mencioné, a veces volvía al día siguiente y Hibernate no cargaba el campo foobar. No entiendo por qué no funcionó todo el tiempo o no funcionaba ninguna de las veces.

En segundo lugar, cuando trataba de deshacerse de esta jerarquía con el fin de eliminar una fuente del problema, que combinó AbstractBar y NewBar pero se olvidó de llevar el @Embeddable desde AbstractBar a NewBar, de modo de hibernación no vio que era una clase incrustable, y no sabía cómo cargar una cadena en un campo NewBar sin una designación @Embeddable. Es por eso que OtherBar (con una anotación @Embeddable) funcionó, pero no NewBar (sin la anotación @Embeddable). Esto mucho lo entiendo. Por qué Hibernate no me advirtió que no podía entender cómo cargar un campo, no lo sé.

Resumiendo, Hibernate no cargará un campo incrustable si dejó la anotación @Embeddable fuera de la clase. En cuanto al problema original, solo puedo adivinar que @Embeddable es escamoso cuando intento usarlo en una jerarquía de clases, y que es mejor que mantenga todos sus campos incrustables en un nivel en la clase incrustable. Espero que ese sea el problema. Veremos si continúa funcionando mañana.

Cuestiones relacionadas