2009-02-14 13 views
10

Tengo problemas para eliminar un elemento de una lista. La lista se define en una superclase, pero las anotaciones de Hibernate se aplican a los descriptores de acceso de propiedades en una subclase. Hay dos métodos en la superclase que manipulan la lista. El método "agregar" funciona bien, pero el "quitar" no persiste los cambios. Revisé la configuración de Cascade y parece que tengo las cosas correctas. Estoy haciendo algo que es imposible. Si no, ¿estoy haciendo algo incorrectamente?Hibernar: Quitar elemento de una lista no persiste

Éstos son mis clases:.

@Entity 
abstract class Temporal<T> { 
    @Id 
    @GeneratedValue 
    private Long id; 

    @Version 
    private Integer version = null; 

    @Transient 
    protected List<T> content = new ArrayList<T>(); 

    public void remove(T value) { 
     // business logic ... 
     content.remove(value); 
    } 

    public void add(T value) { 
     // business logic ... 
     content.add(value); 
    } 
} 

@Entity 
@AccessType("property") 
class TemporalAsset extends Temporal<Asset> { 
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "temporal") 
    public List<Asset> getContent() { 
     return super.content; 
    } 

    protected void setContent(List<Asset> list) { 
     super.content = list; 
    } 
} 

utilizo una instancia de la clase TemporalAsset de la siguiente manera (nótese que sólo estoy uso el método de "refresh" para demostrar el comportamiento La lista no persiste correctamente incluso si limpio o cierro la sesión y abro una nueva sesión):

temporalAsset.add(value1); 
temporalAsset.getContent().size() == 1; // true 
session.update(temporalAsset); 

session.refresh(temporalAsset); 

temporalAsset.getContent().size() == 1; // true 

temporalAsset.remove(value1); 
temporalAsset.getContent().size() == 0; // true 
session.update(temporalAsset); 

session.refresh(temporalAsset); 

temporalAsset.getContent().size() == 0; // false, its 1 

Gracias.

Respuesta

14

Hay que especificar explícitamente en cascada como CascadeType.DELETE_ORPHAN.

tratar de cambiar el código para

@OneToMany  
@Cascade(cascade = {CascadeType.ALL, CascadeType.DELETE_ORPHAN}, mappedBy = "temporal") 

Parte de hibernación docs:

Si la vida útil del objeto secundario se limitada por el tiempo de vida del objeto padre , hacen a los padres una completa objeto de ciclo de vida especificando CascadeType.ALL y org.hibernate.annotations.CascadeType.DELETE_ORPHAN (consulte la guía de referencia de Hibernate para la semántica de huérfano borrar)

+0

¡Eso fue todo! muchas gracias – codefinger

+0

CascadeType.DELETE_ORPHAN está en desuso. ¿Hay una alternativa? –

+5

usa @OneToOne (orphanRemoval = true) o @OneToMany (orphanRemoval = true) de acuerdo con http://docs.jboss.org/hibernate/orm/3.5/api/org/hibernate/annotations/CascadeType.html – FoxyBOA

0

Intenta eliminar las llamadas a Session.refresh(). De los documentos:

Vuelva a leer el estado de la instancia dada de la base de datos subyacente. No es aconsejable usar esto para implementar sesiones de larga duración que abarcan muchas tareas comerciales. Este método es, sin embargo, útil en ciertas circunstancias especiales . Por ejemplo

  • donde un trigger altera el estado del objeto a insertar o actualizar
  • después de ejecutar SQL directa (por ejemplo. Una actualización de masa) en la misma sesión
  • después de insertar un Blob o Clob

http://www.hibernate.org/hib_docs/v3/api/org/hibernate/Session.html#refresh(java.lang.Object)

Si se llama a flush() antes de refresco(), que podrían solucionar el problema también, ya ras () garantiza que cualquier SQL pendiente se ejecutará contra el DB. En la práctica, casi nunca he visto a nadie usar refresh() y su código no parece que lo necesite.

Este capítulo de la documentación es digno de una lectura:

http://www.hibernate.org/hib_docs/v3/reference/en/html/objectstate.html

+0

Solo incluí la actualización aquí para demostrar el comportamiento. En la práctica, el lavado no persiste los cambios en la lista. Incluso puedo cerrar la sesión, abrir una nueva sesión y la lista todavía tiene el valor. – codefinger

0

que haya marcado el campo 'contenido' como transitorio en la superclase. Al menos sospecharía que esto está causando problemas. Con el mapeo en la subclase, básicamente tienes ahora dos asignaciones contradictorias para el mismo atributo.

+0

podrías pensar , pero eso no causa ningún problema – codefinger

Cuestiones relacionadas