Hibernate deleting orphans when updating collection

Marty Pitt picture Marty Pitt · Aug 20, 2009 · Viewed 54.7k times · Source

I'm finding that orphan records aren't being deleted when removing from a collection in Hibernate. I must be doing something simple wrong, (this is Hibernate-101!), but I can't find it..

Given the following:

public class Book {
    @ManyToOne
    @NotNull
    Author author;
}
public class Author
{
    @OneToMany(cascade={CascadeType.ALL})
    List<Book> books;
}

And the following update code:

Author author = authorDAO.get(1);
Book book = author.getBooks().get(0);
author.getBooks().remove(0);
authorDAO.update(author);

AuthorDAO snippet:

@Override
public void update(T entity) {
    getSession().update(entity);
}

The following test the fails:

Author author = author.get(1);
assertEquals(0,author.getBooks().size()); // Passes
Book dbBook = bookDAO.get(book.getId())
assertNull(dbBook); // Fail!  dbBook still exists!
assertFalse(author.getBooks().contains(dbBook) // Passes!

In summary, I'm finding:

  • While book is removed from the Author's collection of books, it still exists in the database
  • If I examine book.getAuthor().getBooks(), book does not exist in that collection

This "feels" like I'm not flushing the session or forcing an update appropriately - but I'm not sure where I should be doing that. Along that vein, other points that may be impacting:

  • I'm performing the above in a JUnit test decorated with @RunWith(SpringJUnit4ClassRunner.class)
  • I originally hit this problem inside an update routine which is decorated with @Transactional, however, I have since recreated it in a plain old JUnit test.

Any advice would be greatly appreciated!

EDIT: Thanks for all the feedback already. Further to comments below, I've added the @Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN) to the parent, so it's now:

public class Author
{
    @OneToMany(cascade={CascadeType.ALL})
    @Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
    List<Book> books;
}

I'm still finding the same results. I MUST be missing something simple.

Answer

Jakub picture Jakub · Dec 12, 2012

for people searching for their solution: Now in Hibernate, resp. JPA 2.0, this is the right way:

@OneToMany(orphanRemoval=true)