16 votes

Une collection avec cascade="all-delete-orphan" n'était plus référencée par l'instance d'entité propriétaire

Dans mon application, une opération hibernate se déroule comme suit. L'application met à jour une entité parent avec les nouvelles valeurs de la requête et supprime toutes les entités enfants existantes (précédemment insérées) et insère de nouveaux enregistrements enfants.

J'utilise des hibernations DELETE_ORPHAN pour cela, comme vous pouvez le voir ci-dessous.

Lorsque je fais cela, j'obtiens l'exception suivante :

org.hibernate.HibernateException : Une collection avec cascade="all-delete-orphan" n'était plus référencée par la collection propriétaire. l'instance d'entité propriétaire : com.childs

J'ai vu des fils de discussion similaires avec ce problème, et j'ai essayé d'appliquer des solutions dans ces fils de discussion. Mais cela n'a pas fonctionné

Mon entité parentale

    public class Parent implements Serializable {

            @Column(name = "PARENT_ID")
            @Basic(fetch = FetchType.EAGER)
            @Id
            @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq")
            @SequenceGenerator(name = "seq", sequenceName = "seq")
            private Integer parentId;  //primary key of parent

            ....... 
            ........

            //mapping to child entity
            @OneToMany(mappedBy = "parent", cascade = { CascadeType.ALL }, fetch =  FetchType.LAZY)
            @Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
            private Set<Child> childs;

            ................
            ...............

}

L'entité Child a une clé combinée et une entité PK, comme indiqué ci-dessous.

public class ChildPK implements Serializable {

    /** The Constant serialVersionUID. */
    private static final long serialVersionUID = -447592368963477750L;

    /** . */
    @ManyToOne(cascade = { CascadeType.ALL }, fetch = FetchType.LAZY)
    @JoinColumns( { @JoinColumn(name = "PARENT_ID", referencedColumnName = "PARENT_ID") })
    @Id
    private Parent parent;

    /**. */

    @Column(name = "CHILD_ID")
    @Basic(fetch = FetchType.EAGER)
    @Id
    @GenericGenerator(name="child_seq",    strategy="com.DB2Dialect") 
    @GeneratedValue(generator="child_seq") 
    private Integer childId;

}

child entity goes like this:

public class Child implements Serializable {

    /** The Constant serialVersionUID. */
    private static final long serialVersionUID = 185670997643552301L;

    /** The pol cntct id. */
    @Column(name = "CHILD_ID")
    @Basic(fetch = FetchType.EAGER)
    @Id
    private Integer childId;

    @ManyToOne(cascade = { CascadeType.ALL }, fetch = FetchType.LAZY)
    @JoinColumns( { @JoinColumn(name = "PARENT_ID", referencedColumnName = "PARENT_ID") })
    @Id
    private Parent parent;

}

Code Java

   ...................
    ..............
    parent.getChild().clear();
    Child child = new Child(); 
    parent.setChild(child);

Qu'est-ce qui pourrait être faux ici.
Merci d'avance...

57voto

JB Nizet Points 250258

Votre dernier bout de code Java ne compile pas. Je suppose que ça ressemble à

parent.getChilds().clear(); // note: you should name it children rather than childs
parent.setChilds(someNewSetOfChildren):

Ne faites pas la dernière instruction. Au lieu de remplacer l'ensemble par un autre, effacez l'ensemble et ajoutez les nouveaux enfants à l'ensemble effacé :

parent.clearChildren();
parent.addChildren(someNewSetOfChildren);

où les méthodes sont définies comme suit :

public void clearChildren() {
    this.children.clear();
}

public void addChildren(Collection<Child> children) {
    this.children.addAll(children);
}

La méthode setChildren doit être supprimée complètement, ou remplacée par l'implémentation suivante :

public void setChildren(Collection<Child> children) {
    this.children.clear();
    this.children.addAll(children);
}

19voto

Hany Sakr Points 594

J'ai rencontré le même problème et l'ai résolu comme suit :

1- ajouter {CascadeType.ALL}, orphanRemoval=true en tout @OneToMany dans tous les enfants de l'entité de cet élément.

2- Vérifier le hashcode() y equalls() de ces entités, parfois ils ont des erreurs.

3- Ne pas utiliser parent.setChilds(newChilds); car le moteur demandera de manquer la référence aux enfants, mais utilisez plutôt

parent.getChilds().clear();
parent.getChilds().add(Child);

o

parent.getChilds().addAll(Childs);

Ces étapes ont résolu mon problème après 4 heures de recherche.

12voto

Venkat Jella Points 121

Ça a marché pour moi.

  1. J'ai effacé toutes mes entités enfant.
  2. Au lieu de fixer les nouvelles entités enfants à mon objet parent, j'ai utilisé la méthode addAll pour ajouter les nouvelles entités enfants.

    parent.getChildren().clear();
    parent.getChildren().addAll(newChildrenList);
    
    @OneToMany(mappedBy = "parent", fetch = FetchType.LAZY, 
               cascade = CascadeType.ALL, orphanRemoval = true)  
    
    public Set<Children> getChildren() {
        return this.children;
    }

8voto

mathi Points 176

Au lieu de setChilds utiliser addAll ,

à partir de ça,

    parent.getChilds().clear();
    parent.setChilds(newChilds);

à

    parent.getChilds().clear();
    parent.getChilds().addAll(newChilds);

0voto

Le changement fonctionne !

@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "user_id")
private List<Role> roles;

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X