16

In my application, a hibernate operation goes like this. The application updates a parent entity with new values from the request and deletes all the existing (previously inserted) child entities and inserts new child records.

I'm using hibernates DELETE_ORPHAN for this, as you can see below.

When i do this, I'm getting the below exception :

org.hibernate.HibernateException: A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance: com.childs

I saw similar threads with the problem, and I tried to appy solutions in those threads. But that didn't work

My Parent entity

    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;

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

}

Child entity has a combined key and has a PK entity has shown below

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;

}

Java code

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

What could be wrong here.
Thanks in advance...

Balasubramanian
  • 700
  • 7
  • 26
user957183
  • 417
  • 3
  • 10
  • 20
  • Possible duplicate of [Hibernate - A collection with cascade=”all-delete-orphan” was no longer referenced by the owning entity instance](https://stackoverflow.com/questions/5587482/hibernate-a-collection-with-cascade-all-delete-orphan-was-no-longer-referenc) – Jens Schauder Mar 15 '19 at 06:48

5 Answers5

57

Your last snippet of Java code doesn't compile. I guess it looks like

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

Don't do the last instruction. Instead of replacing the set by another one, clear the set and add the new children to the cleared set:

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

where the methods are defined as:

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

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

The setChildren method should be removed completely, or it should be replaced with the following implementation:

public void setChildren(Collection<Child> children) {
    this.children.clear();
    this.children.addAll(children);
}
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • For @JBNizet I have a similar problem and I applied your solution. Actually, from the 2 solutions you indicated I used the later (in the setter method I clear the children collection - this.children.clear() - and I added the new children - this.children.addAll(children)). This change didn't fix my problem. I still get the "A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance" exception. Do you have an idea why? Thank you very much! – ovdsrn Dec 12 '12 at 10:37
  • No, I have no idea. You could ask a question, showing your code, the complete stack trace, etc. – JB Nizet Dec 12 '12 at 15:26
  • 1
    Perhaps in `setChildren` null check should be added `if (children != null) { this.children.addAll(children);}` – Marko Vranjkovic Mar 24 '16 at 12:40
  • @lolotron IMO, children should never be null. And ignoring the new children if it is is worse than throwing an NPE to signal the bug – JB Nizet Mar 24 '16 at 13:05
19

I faced the same issue and get it solved as follows:

1- add {CascadeType.ALL}, orphanRemoval=true in all @OneToMany annotations in all entity Childs of that element.

2- Check the hashcode() and equalls() of those entities, some times they have erros

3- Don't use parent.setChilds(newChilds); as the engine will ask for missing the reference to the childs, but use instead use

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

or

parent.getChilds().addAll(Childs);

Those steps solved my issue after 4 Hours of research

Hany Sakr
  • 2,591
  • 28
  • 27
12

It worked for me.

  1. Cleared all my child entities.
  2. Instead of setting the new child entities to my parent object, I have used addAll method to add the new child entities.

    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;
    }
    
Venkat Jella
  • 121
  • 1
  • 3
8

instead of setChilds use addAll ,

from this,

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

to

    parent.getChilds().clear();
    parent.getChilds().addAll(newChilds);
Tom11
  • 2,419
  • 8
  • 30
  • 56
mathi
  • 1,127
  • 12
  • 19
0

it change works !

@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "user_id")
private List<Role> roles;
Ardent Coder
  • 3,777
  • 9
  • 27
  • 53