Hibernar: la instancia de entidad propietaria ya no hace referencia a una colección con cascade=”all-delete-orphan”
Tengo el siguiente problema al intentar actualizar mi entidad:
"A collection with cascade=”all-delete-orphan” was no longer referenced by the owning entity instance".
Tengo una entidad matriz y tiene Set<...>
algunas entidades secundarias. Cuando intento actualizarlo, obtengo que todas las referencias se establezcan en estas colecciones y las configuro.
El siguiente código representa mi mapeo:
@OneToMany(mappedBy = "parentEntity", fetch = FetchType.EAGER)
@Cascade({ CascadeType.ALL, CascadeType.DELETE_ORPHAN })
public Set<ChildEntity> getChildren() {
return this.children;
}
Intenté limpiar el Conjunto<..> únicamente, de acuerdo con esto: Cómo "posible" resolver el problema pero no funcionó.
Si tienes alguna idea, házmelo saber.
¡Gracias!
Verifique todos los lugares donde está asignando algo a sonEntities. El enlace al que hizo referencia señala claramente la creación de un nuevo HashSet, pero puede tener este error cada vez que reasigne el conjunto. Por ejemplo:
public void setChildren(Set<SonEntity> aSet)
{
this.sonEntities = aSet; //This will override the set that Hibernate is tracking.
}
Por lo general, sólo desea "nuevo" el conjunto una vez en un constructor. Cada vez que desee agregar o eliminar algo a la lista, deberá modificar el contenido de la lista en lugar de asignar una nueva lista.
Para agregar niños:
public void addChild(SonEntity aSon)
{
this.sonEntities.add(aSon);
}
Para eliminar niños:
public void removeChild(SonEntity aSon)
{
this.sonEntities.remove(aSon);
}
El método:
public void setChildren(Set<SonEntity> aSet) {
this.sonEntities = aSet;
}
Funciona si se parentEntity
desconecta y nuevamente si lo actualizamos.
Pero si la entidad no está separada de cada contexto (es decir, las operaciones de búsqueda y actualización están en la misma transacción), el siguiente método funciona.
public void setChildren(Set<SonEntity> aSet) {
//this.sonEntities = aSet; //This will override the set that Hibernate is tracking.
this.sonEntities.clear();
if (aSet != null) {
this.sonEntities.addAll(aSet);
}
}
Cuando leí en varios lugares que a Hibernate no le gustaba que lo asignaras a una colección, supuse que lo más seguro obviamente sería hacerlo definitivo de esta manera:
class User {
private final Set<Role> roles = new HashSet<>();
public void setRoles(Set<Role> roles) {
this.roles.retainAll(roles);
this.roles.addAll(roles);
}
}
Sin embargo, esto no funciona y aparece el temido error "ya no se hace referencia", que en realidad es bastante engañoso en este caso.
Resulta que hibernate llama a su método setRoles Y quiere que su clase de colección especial se instale aquí, y no aceptará su clase de colección. Esto me dejó perplejo durante MUCHO tiempo, a pesar de leer todas las advertencias sobre no asignar a su colección en su método establecido.
Entonces cambié a esto:
public class User {
private Set<Role> roles = null;
public void setRoles(Set<Role> roles) {
if (this.roles == null) {
this.roles = roles;
} else {
this.roles.retainAll(roles);
this.roles.addAll(roles);
}
}
}
De modo que en la primera llamada, hibernate instala su clase especial, y en llamadas posteriores puedes usar el método tú mismo sin arruinarlo todo. Si desea utilizar su clase como un bean, probablemente necesite un configurador que funcione, y esto al menos parece funcionar.
Lo arreglé haciendo esto:
1. borre la lista de niños existentes para eliminarlos de la base de datos
parent.getChildren().clear();
2. agregue la nueva lista de niños creada anteriormente a la lista existente
parent.getChildren().addAll(children);
Espero que esta publicación te ayude a resolver el error.