Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA: unidirectional many-to-one and cascading delete

Say I have a unidirectional @ManyToOne relationship like the following:

@Entity public class Parent implements Serializable {      @Id     @GeneratedValue     private long id; }  @Entity public class Child implements Serializable {      @Id     @GeneratedValue     private long id;      @ManyToOne     @JoinColumn     private Parent parent;   } 

If I have a parent P and children C1...Cn referencing back to P, is there a clean and pretty way in JPA to automatically remove the children C1...Cn when P is removed (i.e. entityManager.remove(P))?

What I'm looking for is a functionality similar to ON DELETE CASCADE in SQL.

like image 601
perp Avatar asked Aug 25 '11 21:08

perp


People also ask

What is JPA orphanRemoval?

orphanRemoval is an entirely ORM-specific thing. It marks "child" entity to be removed when it's no longer referenced from the "parent" entity, e.g. when you remove the child entity from the corresponding collection of the parent entity.

What is bidirectional relationship JPA?

Overview. JPA Relationships can be either unidirectional or bidirectional. This simply means we can model them as an attribute on exactly one of the associated entities or both. Defining the direction of the relationship between entities has no impact on the database mapping.

What is orphanRemoval?

Such target entities are considered “orphans,” and the orphanRemoval attribute can be used to specify that orphaned entities should be removed. For example, if an order has many line items and one of them is removed from the order, the removed line item is considered an orphan.

How does JPA represent many to many relationships?

In JPA we use the @ManyToMany annotation to model many-to-many relationships. This type of relationship can be unidirectional or bidirectional: In a unidirectional relationship only one entity in the relationship points the other. In a bidirectional relationship both entities point to each other.


2 Answers

If you are using hibernate as your JPA provider you can use the annotation @OnDelete. This annotation will add to the relation the trigger ON DELETE CASCADE, which delegates the deletion of the children to the database.

Example:

public class Parent {             @Id         private long id;  }   public class Child {                  @Id         private long id;            @ManyToOne         @OnDelete(action = OnDeleteAction.CASCADE)         private Parent parent; }       

With this solution a unidirectional relationship from the child to the parent is enough to automatically remove all children. This solution does not need any listeners etc. Also a JPQL query like DELETE FROM Parent WHERE id = 1 will remove the children.

like image 113
Thomas Hunziker Avatar answered Oct 13 '22 07:10

Thomas Hunziker


Relationships in JPA are always unidirectional, unless you associate the parent with the child in both directions. Cascading REMOVE operations from the parent to the child will require a relation from the parent to the child (not just the opposite).

You'll therefore need to do this:

  • Either, change the unidirectional @ManyToOne relationship to a bi-directional @ManyToOne, or a unidirectional @OneToMany. You can then cascade REMOVE operations so that EntityManager.remove will remove the parent and the children. You can also specify orphanRemoval as true, to delete any orphaned children when the child entity in the parent collection is set to null, i.e. remove the child when it is not present in any parent's collection.
  • Or, specify the foreign key constraint in the child table as ON DELETE CASCADE. You'll need to invoke EntityManager.clear() after calling EntityManager.remove(parent) as the persistence context needs to be refreshed - the child entities are not supposed to exist in the persistence context after they've been deleted in the database.
like image 44
Vineet Reynolds Avatar answered Oct 13 '22 05:10

Vineet Reynolds