it-swarm.com.de

Ruhezustand - Eine Sammlung mit cascade = "all-delete-Orphan" wurde nicht mehr von der Eigentümerinstanz referenziert

Beim Versuch, mein Unternehmen zu aktualisieren, tritt folgendes Problem auf:

"A collection with cascade=”all-delete-Orphan” was no longer referenced by the owning entity instance".

Ich habe eine übergeordnete Entität und es gibt einen Set<...> einiger untergeordneter Entitäten. Wenn ich versuche, es zu aktualisieren, bekomme ich alle Referenzen, die auf diese Sammlungen gesetzt werden sollen, und setze sie.

Der folgende Code steht für meine Zuordnung:

@OneToMany(mappedBy = "parentEntity", fetch = FetchType.EAGER)
@Cascade({ CascadeType.ALL, CascadeType.DELETE_Orphan })
public Set<ChildEntity> getChildren() {
    return this.children;
}

Ich habe versucht, das Set <..> nur entsprechend zu säubern: Wie lässt sich das Problem "möglich" lösen aber es hat nicht funktioniert.

Wenn Sie irgendwelche Ideen haben, lass es mich wissen.

Vielen Dank!

164
axcdnt

Eigentlich ging es mir um Gleichberechtigte und Hashcode meiner Entitäten. Ein älterer Code kann viele Probleme mit sich bringen. Vergessen Sie nicht, es auszuprobieren. Alles, was ich getan habe, war einfach die Delete-Orphan-Strategie beizubehalten.

14
axcdnt

Überprüfen Sie alle Orte, an denen Sie sonEntities etwas zuweisen. Der Link, auf den Sie verwiesen haben, weist eindeutig darauf hin, dass Sie ein neues HashSet erstellen, aber Sie können diesen Fehler jedes Mal haben, wenn Sie das Set neu zuweisen. Zum Beispiel:

public void setChildren(Set<SonEntity> aSet)
{
    this.sonEntities = aSet; //This will override the set that Hibernate is tracking.
}

Normalerweise möchten Sie die Menge nur einmal in einem Konstruktor "neu" machen. Wenn Sie der Liste etwas hinzufügen oder löschen möchten, müssen Sie den Inhalt der Liste ändern, anstatt eine neue Liste zuzuweisen.

Kinder hinzufügen:

public void addChild(SonEntity aSon)
{
    this.sonEntities.add(aSon);
}

So entfernen Sie Kinder:

public void removeChild(SonEntity aSon)
{
    this.sonEntities.remove(aSon);
}
170
brainimus

Die Methode:

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

funktioniert, wenn die parentEntity getrennt ist und erneut, wenn wir sie aktualisieren.
Wenn jedoch die Entität nicht vom Kontext getrennt wird (d. H. Such- und Aktualisierungsoperationen in derselben Transaktion sind), funktioniert die unten stehende Methode.

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);
    }
}
83
Manu

Wenn ich an verschiedenen Stellen las, dass der Winterschlaf Ihnen nicht gefällt, einer Sammlung zuzuordnen, ging ich davon aus, dass es am sichersten wäre, wenn Sie es so finalisieren:

class User {
  private final Set<Role> roles = new HashSet<>();

public void setRoles(Set<Role> roles) {
  this.roles.retainAll(roles);
  this.roles.addAll(roles);
}
}

Dies funktioniert jedoch nicht, und Sie erhalten den gefürchteten Fehler "nicht mehr referenziert", der in diesem Fall ziemlich irreführend ist.

Es stellt sich heraus, dass der Ruhezustand Ihre setRoles-Methode aufruft UND seine spezielle Collection-Klasse hier installiert werden soll und Ihre Collection-Klasse nicht akzeptiert. Dies hatte mich lange Zeit überfordert, obwohl ich alle Warnungen gelesen hatte, dass Sie Ihre Sammlung nicht in Ihrer set-Methode zugewiesen hatten.

Also habe ich das geändert:

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);
  }
}
}

Damit installiert Hibernate beim ersten Aufruf seine spezielle Klasse, und bei nachfolgenden Aufrufen können Sie die Methode selbst verwenden, ohne alles zu zerstören. Wenn Sie Ihre Klasse als Bean verwenden möchten, benötigen Sie wahrscheinlich einen funktionierenden Setzer, und dies scheint zumindest zu funktionieren.

21
user2709454

Ich hatte den gleichen Fehler. Das Problem für mich war, dass nach dem Speichern der Entität die zugeordnete Sammlung immer noch null war und beim Versuch, die Entität zu aktualisieren, die Ausnahme ausgelöst wurde. Was für mich geholfen hat: Speichern der Entität, dann Aktualisieren (Auflistung ist nicht mehr null) und dann das Update durchführen. Vielleicht hilft es auch, die Collection mit new ArrayList () oder etwas zu initialisieren.

9
Konsumierer

hat Beziehungstyp:


Versuchen Sie nicht, die Collection zu instanziieren, wenn sie in hasMany deklariert ist. 

class Parent {
    static hasMany = [childs:Child]
}

VERWENDUNGSTYP:


Die Auflistung kann jedoch nur dann null sein, wenn sie als Eigenschaft deklariert ist (use relation) und nicht in der Deklaration initialisiert wird.

class Parent {
    List<Child> childs = []
}
4
IgniteCoders

Ich hatte dieses Problem, als ich TreeSet verwendete. Ich habe oneToMany mit TreeSet initialisiert, was funktioniert

@OneToMany(mappedBy = "question", fetch = FetchType.EAGER, cascade = { CascadeType.ALL }, orphanRemoval=true)
@OrderBy("id")
private Set<WizardAnswer> answers = new TreeSet<WizardAnswer>();

Dies führt jedoch zu dem in der Variablen question beschriebenen Fehler. Es scheint also, dass hibernateSortedSet unterstützt und wenn man nur die Zeile darüber ändert

@OneToMany(mappedBy = "question", fetch = FetchType.EAGER, cascade = { CascadeType.ALL }, orphanRemoval=true)
@OrderBy("id")
private SortedSet<WizardAnswer> answers;

es funktioniert wie magisch:) Weitere Informationen zu hibernate SortedSet können hier

3
oak

Diese Fehlermeldung wird nur angezeigt, wenn ich versuche, NULL an den Setter für die Sammlung zu übergeben. Um dies zu verhindern, sehen meine Setter folgendermaßen aus:

public void setSubmittedForms(Set<SubmittedFormEntity> submittedForms) {
    if(submittedForms == null) {
        this.submittedForms.clear();
    }
    else {
        this.submittedForms = submittedForms;
    }
}
2
Arlo Guthrie

Ich benutzte den Ansatz @ user2709454 mit einer kleinen Verbesserung.

public class User {
    private Set<Role> roles;

    public void setRoles(Set<Role> roles) {
        if (this.roles == null) {
            this.roles = roles;
        } else if(this.roles != roles) { // not the same instance, in other case we can get ConcurrentModificationException from hibernate AbstractPersistentCollection
            this.roles.clear();
            if(roles != null){
                this.roles.addAll(roles);
            }
        }
    }
}
2
luwojtaszek

Eine andere Ursache kann Lombok sein.

@Builder - bewirkt das Speichern von Collections.emptyList(), auch wenn Sie .myCollection(new ArrayList()); sagen

@Singular - ignoriert die Standardwerte auf Klassenebene und verlässt das Feld null, auch wenn das Klassenfeld als myCollection = new ArrayList() deklariert wurde

Meine 2 Cent, gerade 2 Stunden mit dem gleichen verbracht :)

0
Jan Zyka
@OneToMany(mappedBy = 'parent', cascade= CascadeType.ALL, orphanRemoval = true)
List<Child> children = new ArrayList<>()

Der gleiche Fehler trat auf, als ich der vorhandenen Liste der untergeordneten Objekte ein untergeordnetes Objekt hinzufügte.

childService.saveOrUpdate(child);
parent.addToChildren(child);
parentService.saveOrUpdate(parent);

Was mein Problem gelöst hat, ist: child = childService.saveOrUpdate (child);

Nun ist das Kind mit weiteren Details wiederbelebt und es hat gut funktioniert.

0
Neha Gupta

Ich habe A collection with cascade=”all-delete-Orphan” was no longer referenced by the owning entity instance bekommen, als ich parent.setChildren(new ArrayList<>()) eingestellt habe. Als ich zu parent.getChildren().clear() wechselte, wurde das Problem gelöst.

Weitere Informationen finden Sie hier: HibernateException - Eine Auflistung mit cascade = "all-delete-Orphan" wurde nicht mehr von der Eigentümerinstanz referenziert.

0
Justas

Meine dumme Antwort hinzufügen. Wir verwenden Spring Data Rest. Dies war unsere ziemlich normale Beziehung. Das Muster wurde an anderer Stelle verwendet. 

//Parent class
@OneToMany(mappedBy = 'parent', 
           cascade= CascadeType.ALL, orphanRemoval = true)
@LazyCollection(LazyCollectionOption.FALSE)
List<Child> children = new LinkedList<>()


//Child class
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = 'ParentID', updatable = false)
@JsonBackReference
Parent parent

Bei der von uns geschaffenen Beziehung war es immer beabsichtigt, dass die Kinder durch ihr eigenes Repo hinzugefügt werden. Ich hatte das Repo noch nicht hinzugefügt. Der durchgeführte Integrationstest durchlief einen vollständigen Lebenszyklus der Entität über REST - Aufrufe, sodass die Transaktionen zwischen Anforderungen geschlossen wurden. Kein Repo für das Kind bedeutete, dass der Json die Kinder als Teil der Hauptstruktur anstelle von _embedded hatte. Updates für das übergeordnete Element würden dann Probleme verursachen.

0
Snekse

Folgende Lösung hat bei mir funktioniert

//Parent class
@OneToMany(mappedBy = 'parent', 
           cascade= CascadeType.ALL, orphanRemoval = true)
@OrderBy(value="ordinal ASC")
List<Child> children = new ArrayList<>()

//Updated setter of children 
public void setChildren(List<Children> children) {
    this.children.addAll(children);
    for (Children child: children)
        child.setParent(this);
}


//Child class
@ManyToOne
@JoinColumn(name="Parent_ID")
private Parent parent;
0
priyanka_rao

Es kann durch hibernate-enhance-maven-plugin verursacht werden. Wenn ich die enableLazyInitialization-Eigenschaft aktivierte, begann diese Ausnahme in meiner Lazy-Collection. Ich verwende Hibernate 5.2.17.Final.

Beachten Sie diese zwei Probleme mit dem Ruhezustand:

0

sei vorsichtig mit 

BeanUtils.copyProperties(newInsum, insumOld,"code");

Auch diese Methode durchbricht den Winterschlaf.

0

Ich bin beim Aktualisieren einer Entität mit einer JSON-Post-Anfrage darauf gestoßen. Der Fehler trat auf, als ich die Entität ohne Daten zu den untergeordneten Elementen aktualisierte, auch wenn keine vorhanden waren. Hinzufügen

"children": [],

an den anfragetext hat das problem gelöst.

0
co ting

Anstatt eine neue Sammlung zuzuweisen

public void setChildren(Set<ChildEntity> children) {
    this.children = children;
}

Ersetzen Sie alle Elemente mit

public void setChildren(Set<ChildEntity> children) {
    Collections.replaceAll(this.children,children);
}
0
Marcin Szymczak

Meins war ganz anders mit Spring Boot! Für mich lag es nicht am Festlegen der Sammlungseigenschaft.

In meinen Tests habe ich versucht, eine Entität zu erstellen und habe diesen Fehler für eine andere Sammlung erhalten, die nicht verwendet wurde!

Nach so vielen Versuchen habe ich einfach einen @Transactional zur Testmethode hinzugefügt und es wurde behoben. Aber nicht den Grund.

0
madz

Ich verwende Spring Boot und hatte dieses Problem mit einer Sammlung, obwohl es nicht direkt überschrieben wurde, da ich ein zusätzliches Feld für dieselbe Sammlung mit einem benutzerdefinierten Serializer und Deserializer deklariere, um ein weiteres anzugeben Frontend-freundliche Darstellung der Daten:

  public List<Attribute> getAttributes() {
    return attributes;
  }

  public void setAttributes(List<Attribute> attributes) {
    this.attributes = attributes;
  }

  @JsonSerialize(using = AttributeSerializer.class)
  public List<Attribute> getAttributesList() {
    return attributes;
  }

  @JsonDeserialize(using = AttributeDeserializer.class)
  public void setAttributesList(List<Attribute> attributes) {
    this.attributes = attributes;
  }

Es scheint, dass, obwohl ich die Sammlung yourself nicht überschreibe, die Deserialisierung dies unter der Haube tut und dieses Problem trotzdem auslöst. Die Lösung bestand darin, den mit dem Deserializer verknüpften Setter so zu ändern, dass er die Liste löscht und alles hinzufügt, anstatt sie zu überschreiben:

  @JsonDeserialize(using = AttributeDeserializer.class)
  public void setAttributesList(List<Attribute> attributes) {
    this.attributes.clear();
    this.attributes.addAll(attributes);
  }
0
Sofia Paixão