Hibernar: la instancia de entidad propietaria ya no hace referencia a una colección con cascade=”all-delete-orphan”

Resuelto axcdnt asked hace 13 años • 33 respuestas

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!

axcdnt avatar Apr 08 '11 03:04 axcdnt
Aceptado

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);
}
brainimus avatar Apr 07 '2011 21:04 brainimus

El método:

public void setChildren(Set<SonEntity> aSet) {
    this.sonEntities = aSet;
}

Funciona si se parentEntitydesconecta 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);
    }
}
Manu avatar Jan 12 '2012 13:01 Manu

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.

xpusostomos avatar Jun 17 '2014 23:06 xpusostomos

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.

Ousama avatar Mar 09 '2021 12:03 Ousama