138

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.

rtruszk
  • 3,868
  • 13
  • 33
  • 53
Paul Whelan
  • 15,841
  • 12
  • 46
  • 79

11 Answers11

166

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)
rtruszk
  • 3,868
  • 13
  • 33
  • 53
Varun Mehta
  • 1,979
  • 3
  • 19
  • 26
  • 3
    thanks I ended up going this route, I think this is a bit of an oversite for the JPA spec. – Paul Whelan Nov 21 '08 at 08:49
  • 13
    The JPA 2.0 standard now has deleteOrphan as an attribute to @OneToMany If you are using the latest hibernate you can do @OneToMany(..., deleteOrphan=true) – jomohke Jun 11 '10 at 06:33
  • what is execution sequence when i just update child-elements? will orphan-records be deleted? – jAckOdE May 26 '14 at 07:22
113

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.

acdcjunior
  • 114,460
  • 30
  • 289
  • 276
Kango_V
  • 1,755
  • 2
  • 14
  • 11
  • 6
    Actually I think orphanRemoval=true means something else, i.e., delete an object when I remove it from it's parent's collection. See http://download.oracle.com/javaee/6/tutorial/doc/bnbqa.html#giqxy – Archie Sep 13 '10 at 22:37
  • Please g through Archie's link. – Jigar Shah Jul 11 '12 at 22:18
  • 4
    **orphanRemoval=true** does not work either. It has to be done the old way. – Joe Almore Jun 15 '13 at 15:17
47
╔═════════════╦═════════════════════╦═════════════════════╗
║   Action    ║  orphanRemoval=true ║   CascadeType.ALL   ║
╠═════════════╬═════════════════════╬═════════════════════╣
║   delete    ║     deletes parent  ║    deletes parent   ║
║   parent    ║     and orphans     ║    and orphans      ║
╠═════════════╬═════════════════════╬═════════════════════╣
║   change    ║                     ║                     ║
║  children   ║   deletes orphans   ║      nothing        ║
║    list     ║                     ║                     ║
╚═════════════╩═════════════════════╩═════════════════════╝
Sergii Shevchyk
  • 35,850
  • 12
  • 46
  • 59
  • 1
    What happens if I have `cascade = CascadeType.ALL, orphanRemoval = false` and delete the parent? Will it delete children, even though I've specifically told NOT to? – izogfif Mar 04 '18 at 11:06
12

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

uı6ʎɹnɯ ꞁəıuɐp
  • 3,273
  • 2
  • 36
  • 46
7

you can use @PrivateOwned to delete orphans e.g

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

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.

CSchulz
  • 10,102
  • 9
  • 54
  • 107
Valéry Stroeder
  • 583
  • 1
  • 5
  • 15
  • 1
    I needed to clean and build before the change came into effect. – maralbjo May 15 '12 at 19:03
  • Wow, I've been looking for an hour as to why adding CascadeType.ALL on my ManyToOne wasn't cascading deletes. Cleaned and built and it works. Thanks @maralbjo. – Andrew Mairose Jun 22 '15 at 18:27
4

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

It is also not supported in JPA XML.

toolkit
  • 47,529
  • 17
  • 103
  • 134
2

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.

Bevor
  • 7,568
  • 11
  • 67
  • 130
2

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

Remove targetEntity = MyClass.class, it works great.

Joffrey
  • 13,071
  • 1
  • 42
  • 68
Kohan95
  • 8,559
  • 4
  • 18
  • 21
1

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

Simone Gianni
  • 10,588
  • 36
  • 45
0

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