Ibernazione: una raccolta con cascade = “all-delete-orphan” non è più referenziata dall’istanza dell’entity framework proprietaria

Sto riscontrando il seguente problema quando provo ad aggiornare la mia quadro:

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

Ho un’entity framework genitore e ha un Set di alcune quadro figli. Quando provo ad aggiornarlo, ottengo tutti i riferimenti da impostare su queste raccolte e impostarlo.

Il seguente codice rappresenta la mia mapping:

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

Ho provato a pulire solo il Set , in base a questo: Come “ansible” risolvere il problema ma non ha funzionato.

Se avete qualche idea, per favore fatemelo sapere.

Grazie!

Controlla tutti i luoghi in cui stai assegnando qualcosa a SonEntities. Il link a cui fai riferimento distingue chiaramente la creazione di un nuovo HashSet ma puoi avere questo errore ogni volta che riassegni il set. Per esempio:

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

Di solito vuoi solo “nuovo” il set una volta in un costruttore. Ogni volta che vuoi aggiungere o cancellare qualcosa alla lista devi modificare il contenuto della lista invece di assegnare una nuova lista.

Per aggiungere bambini:

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

Per rimuovere i bambini:

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

Il metodo:

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

funziona se parentEntity è staccato e di nuovo se lo aggiorniamo.
Ma se l’ quadro non è distaccata dal contesto, (cioè le operazioni di ricerca e aggiornamento si trovano nella stessa transazione) il metodo seguente funziona.

 public void setChildren(Set aSet) { //this.sonEntities = aSet; //This will override the set that Hibernate is tracking. this.sonEntities.clear(); if (aSet != null) { this.sonEntities.addAll(aSet); } } 

Quando ho letto in vari posti che il letargo non mi piaceva da assegnare a una raccolta, ho pensato che la cosa più sicura da fare sarebbe ovviamente quella di renderlo definitivo in questo modo:

 class User { private final Set roles = new HashSet<>(); public void setRoles(Set roles) { this.roles.retainAll(roles); this.roles.addAll(roles); } } 

Tuttavia, questo non funziona, e si ottiene il temuto errore “non più referenziato”, che in realtà è piuttosto fuorviante in questo caso.

Risulta che l’ibernazione chiama il metodo setRoles E vuole che la sua class di raccolta speciale sia installata qui e non accetterà la class della raccolta. Questo mi ha lasciato per un lungo periodo, nonostante avessi letto tutti gli avvertimenti relativi alla mancata assegnazione alla tua raccolta nel tuo metodo set.

Così ho cambiato questo:

 public class User { private Set roles = null; public void setRoles(Set roles) { if (this.roles == null) { this.roles = roles; } else { this.roles.retainAll(roles); this.roles.addAll(roles); } } } 

In questo modo, durante la prima chiamata, Hibernate installa la sua class speciale, e nelle chiamate successive puoi usare il metodo tu stesso senza distruggere tutto. Se vuoi usare la tua class come un fagiolo, probabilmente hai bisogno di un setter funzionante, e questo almeno sembra funzionare.

In realtà, il mio problema riguardava l’uguaglianza e l’hashcode delle mie entity framework. Un codice legacy può portare molti problemi, non dimenticarti mai di verificarlo. Tutto quello che ho fatto è stato mantenere la strategia di cancellazione-orfano e correggere equals e hashcode.

Ho avuto lo stesso errore. Il problema per me era che, dopo aver salvato l’ quadro, la raccolta mappata era ancora nullo e quando si tentava di aggiornare l’ quadro veniva lanciata l’eccezione. Cosa mi ha aiutato: Salvare l’ quadro, quindi eseguire un aggiornamento (la raccolta non è più nulla) e quindi eseguire l’aggiornamento. Forse inizializzare la collezione con la nuova ArrayList () o qualcosa potrebbe essere d’aiuto.

HA TIPO DI RELAZIONE:


Non cercare di hasMany un’istanza della raccolta quando è dichiarata in hasMany , basta aggiungere e rimuovere oggetti.

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

TIPO DI RELAZIONE D’USO:


Ma la raccolta potrebbe essere nullo solo quando è dichiarata come una proprietà (relazione d’uso) e non è inizializzata nella dichiarazione.

 class Parent { List childs = [] } 

Ho avuto questo problema durante il tentativo di utilizzare TreeSet . Ho inizializzato oneToMany con TreeSet che funziona

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

Ma questo porterà l’errore descritto nella question sopra. Quindi sembra che SortedSet supportato SortedSet e se si cambia semplicemente la linea in alto a

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

funziona come per magia 🙂 maggiori informazioni su hibernate SortedSet può essere qui

L’unica volta che ottengo questo errore è quando provo a passare NULL nel setter per la raccolta. Per evitare questo, i miei setter assomigliano a questo:

 public void setSubmittedForms(Set submittedForms) { if(submittedForms == null) { this.submittedForms.clear(); } else { this.submittedForms = submittedForms; } } 

Aggiungendo la mia stupida risposta. Stiamo usando Spring Data Rest. Questa era la nostra bella relazione standard. Il modello è stato usato altrove.

 //Parent class @OneToMany(mappedBy = 'parent', cascade= CascadeType.ALL, orphanRemoval = true) @LazyCollection(LazyCollectionOption.FALSE) List children = new LinkedList<>() //Child class @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = 'ParentID', updatable = false) @JsonBackReference Parent parent 

Con la relazione che abbiamo creato, è stato sempre inteso che i bambini sarebbero stati aggiunti attraverso il loro repository. Non avevo ancora aggiunto il repository. Il test di integrazione che avevamo stava attraversando un ciclo di vita completo dell’ quadro tramite le chiamate REST in modo che le transazioni si sarebbero chiuse tra le richieste. Nessun repo per il bambino significava che il json aveva i figli come parte della struttura principale invece che in _embedded . Gli aggiornamenti al genitore potrebbero quindi causare problemi.

La seguente soluzione ha funzionato per me

 //Parent class @OneToMany(mappedBy = 'parent', cascade= CascadeType.ALL, orphanRemoval = true) @OrderBy(value="ordinal ASC") List children = new ArrayList<>() //Updated setter of children public void setChildren(List children) { this.children.addAll(children); for (Children child: children) child.setParent(this); } //Child class @ManyToOne @JoinColumn(name="Parent_ID") private Parent parent; 

Invece di assegnare una nuova collezione

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

Sostituisci tutti gli elementi con

 public void setChildren(Set children) { Collections.replaceAll(this.children,children); } 

Un’altra causa potrebbe essere l’uso del lombok.

@Builder – causa il salvataggio di Collections.emptyList() anche se si dice .myCollection(new ArrayList());

@Singular – ignora i valori di default del livello di class e lascia il campo null anche se il campo della class è stato dichiarato come myCollection = new ArrayList()

I miei 2 centesimi, ho appena trascorso 2 ore con lo stesso 🙂

Stavo ricevendo A collection with cascade=”all-delete-orphan” was no longer referenced by the owning entity instance parent.setChildren(new ArrayList<>()) A collection with cascade=”all-delete-orphan” was no longer referenced by the owning entity instance quando stavo impostando parent.setChildren(new ArrayList<>()) . Quando ho cambiato in parent.getChildren().clear() , ha risolto il problema.

Verificare ulteriori dettagli: HibernateException – Una raccolta con cascade = “all-delete-orphan” non è più referenziata dall’istanza dell’ quadro proprietaria .

stai attento

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

Anche questo metodo interrompe l’ibernazione.