23

Suppose that we have 3 Entities object class:

class Parent {
    String name;
    List<Child> children;
}

class Child {
    String name;
    Parent parent;
}

class Toy {
    String name;
    Child child;
}

How can I use JPA2.x (or hibernate) annotations to:

  1. Delete all children automatically when parent delete (one to many)
  2. Delete child automatically from children list when it is deleted (many to one)
  3. Delete toy automatically when child remove (one to one)

I'm using Hibernate 4.3.5 and mysql 5.1.30.

Thanks

Vlad Mihalcea
  • 142,745
  • 71
  • 566
  • 911
user1079877
  • 9,008
  • 4
  • 43
  • 54

3 Answers3

36

The remove entity state transition should cascade from parent to children, not the other way around.

You need something like this:

class Parent {

    String name;

    @OneToMany(mappedBy = "parent", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    List<Child> children = new ArrayList<>();

    public void addChild(Child child) {
        child.setParent(this);
        children.add(child);
    }

    public void removeChild(Child child) {
        children.remove(child);
        child.setParent(null);
    }
}

class Child {

    String name;

    @ManyToOne
    Parent parent;
    
    @OneToOne(mappedBy = "child", cascade = CascadeType.ALL, orphanRemoval = true)
    Toy toy;
}

class Toy {
    String name;

    @OneToOne
    Child child;
}
Vlad Mihalcea
  • 142,745
  • 71
  • 566
  • 911
  • I have a weird problem. We I persist or remove something, it just add or remove but next time that I reload the page (query again), it's there, next time disappear again and it continues randomly! When I close EntityManagerFactory (Restart application), everything will be fine! – user1079877 May 29 '14 at 06:31
  • 1
    I updated my response with the add/remove child methods. Make sure you always synchronize both the parent and the child associations, so when you add a new child, both the parent and the child are aware of the new link. Make sure you do those operations inside a Transaction and you should be fine. The EntityManagerFactory should be closed only when your application shut downs. – Vlad Mihalcea May 29 '14 at 06:47
  • With hibernate 3.5.6-Final, no problem!! – user1079877 May 30 '14 at 06:46
  • 1
    Mapping on `List toys` in `Child` is wrong. It should be `OneToMany`. Checkout the comment by [@JB Nizet in this post](http://stackoverflow.com/questions/21762328/java-hibernate-onetoone-mapping/21762450#21762450). Update ur answer. – OO7 Apr 10 '15 at 09:49
  • It should be `Toy toy` and not a `one-to-many` association. Check the question. – Vlad Mihalcea Apr 10 '15 at 09:53
  • 1
    Yes, u r right. It is `OneToOne` & just `Toy` instead of `List toys`. So, *U were wrong before editing answer.* Now it's perfect. – OO7 Apr 10 '15 at 09:57
  • Yes, thanks for pointing that out. Here's a comment up-vote ;) – Vlad Mihalcea Apr 10 '15 at 09:59
  • 1
    It makes sense that you wouldn't want to cascade a delete operation from child to parent, but is there no annotation in hibernate to have a child delete operation cause the reference of the child in the parent collection to be removed? I guess it's fine if there is no such annotation, but considering all of the other things hibernate annotations can do, this doesn't seem unreasonable. – SomeGuy Mar 01 '18 at 20:55
  • I have an extremely similar problem. I followed your advice and got things working partially. However, I ran into another problem soon. Here's my question: https://stackoverflow.com/questions/59230126/cannot-delete-or-update-a-parent-row-a-foreign-key-constraint-fails-when-deleti . It would be awesome if you could help me out a bit. I've been banging my head for over several days now, but can't seem to progress at all. – gourabix Dec 08 '19 at 07:02
10

You should use CascadeType.REMOVE. This is common annotation for both Hibernate and JPA. Hibernate has another similar type CacadeType like CascadeType.DELETE.

  1. Delete all children automatically when parent delete (one to many)

    class Parent {
      String name;
    
      @OneToMany(cascade = CascadeType.REMOVE)
      List<Child> children;
    }
    
  2. Delete child automatically from children list when it is deleted (many to one)

    class Child {
     String name;
     @ManyToOne(cascade = CascadeType.REMOVE)
     Parent parent;
    }
    
  3. Delete toy automatically when child remove (one to one)

    class Toy {
      String name;
      @OneToOne(cascade = CascadeType.REMOVE)
      Child child;
    }
    
Masudul
  • 21,823
  • 5
  • 43
  • 58
  • 12
    Why would you want to cascade the remove from the Child to the Parent, or from the Toy to the Child. This would mean that when I remove a toy, I remove the Child and it's parent with all his children. – Vlad Mihalcea May 29 '14 at 05:44
  • Don't forget to update your database setting to allow cascade for remove operations – Saleh Nov 25 '22 at 07:54
1

orphanRemoval is delete all orphan entity example: store (s) has books(b1,b2,b3) and b1 has title(t) in this case if deleted store(s) some books(b2,b3) will be deleted. B2 and t still exist. if you use "cascade= CascadeType.Remove" just store(s) and all books will be deleted (only "t" exist).

s->b1,b2,b3 b2->t ------after(orphanRemoval = true)--------- b2->t

s->b1,b2,b3 b2->t ------ after(cascade=CascadeType.REMOVE)--------- t

If orphanRemoval=true is specified the disconnected entity instance is automatically removed. This is useful for cleaning up dependent objects that should not exist without a reference from an owner object.

If only cascade=CascadeType.REMOVE is specified no automatic action is taken since disconnecting a relationship is not a remove operation.

Farvardin
  • 5,336
  • 5
  • 33
  • 54