138
votes

I am having trouble deleting orphan nodes using JPA with the following mapping

@OneToMany (cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "owner")
private List<Bikes> bikes;

I am having the issue of the orphaned roles hanging around the database.

I can use the annotation org.hibernate.annotations.Cascade Hibernate specific tag but obviously I don't want to tie my solution into a Hibernate implementation.

EDIT: It seems JPA 2.0 will include support for this.

11

11 Answers

167
votes

If you are using it with Hibernate, you'll have to explicitly define the annotation CascadeType.DELETE_ORPHAN, which can be used in conjunction with JPA CascadeType.ALL.

If you don't plan to use Hibernate, you'll have to explicitly first delete the child elements and then delete the main record to avoid any orphan records.

execution sequence

  1. fetch main row to be deleted
  2. fetch child elements
  3. delete all child elements
  4. delete main row
  5. close session

With JPA 2.0, you can now use the option orphanRemoval = true

@OneToMany(mappedBy="foo", orphanRemoval=true)
113
votes

If you are using JPA 2.0, you can now use the orphanRemoval=true attribute of the @xxxToMany annotation to remove orphans.

Actually, CascadeType.DELETE_ORPHAN has been deprecated in 3.5.2-Final.

47
votes
╔═════════════╦═════════════════════╦═════════════════════╗
║   Action    ║  orphanRemoval=true ║   CascadeType.ALL   ║
╠═════════════╬═════════════════════╬═════════════════════╣
║   delete    ║     deletes parent  ║    deletes parent   ║
║   parent    ║     and orphans     ║    and orphans      ║
╠═════════════╬═════════════════════╬═════════════════════╣
║   change    ║                     ║                     ║
║  children   ║   deletes orphans   ║      nothing        ║
║    list     ║                     ║                     ║
╚═════════════╩═════════════════════╩═════════════════════╝
12
votes

If you are using JPA with EclipseLink, you'll have to set the @PrivateOwned annotation.

Documentation: Eclipse Wiki - Using EclipseLink JPA Extensions - Chapter 1.4 How to Use the @PrivateOwned Annotation

7
votes

you can use @PrivateOwned to delete orphans e.g

@OneToMany(mappedBy = "masterData", cascade = {
        CascadeType.ALL })
@PrivateOwned
private List<Data> dataList;
6
votes

I just find this solution but in my case it doesn't work:

@OneToMany(cascade = CascadeType.ALL, targetEntity = MyClass.class, mappedBy = "xxx", fetch = FetchType.LAZY, orphanRemoval = true) 

orphanRemoval = true has no effect.

4
votes

According to Java Persistence with Hibernate, cascade orphan delete is not available as a JPA annotation.

It is also not supported in JPA XML.

2
votes

I had the same problem and I wondered why this condition below did not delete the orphans. The list of dishes were not deleted in Hibernate (5.0.3.Final) when I executed a named delete query:

@OneToMany(mappedBy = "menuPlan", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Dish> dishes = new ArrayList<>();

Then I remembered that I must not use a named delete query, but the EntityManager. As I used the EntityManager.find(...) method to fetch the entity and then EntityManager.remove(...) to delete it, the dishes were deleted as well.

2
votes

Just @OneToMany(cascade = CascadeType.ALL, mappedBy = "xxx", fetch = FetchType.LAZY, orphanRemoval = true).

Remove targetEntity = MyClass.class, it works great.

1
votes

For the records, in OpenJPA before JPA2 it was @ElementDependant.

0
votes

I was using one to one mapping , but child was not getting deleted JPA was giving foreign key violation

After using orphanRemoval = true , issue got resolved