Saturday, 23 March 2013

JPA 2.0 + Hibernate: OrphanRemoval & CascadeType.REMOVE

Here I am writing to cover up the difference between OrphanRemoval=true and CascadeType.REMOVE in JPA2.0 with hibernate.

Let say there is one to many relationship between User and Address and that can be defined in JPA as below:
public class User{     
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY,
        mappedBy = "user")
    public Set getAddresses() {
       return this.addresses;
    }
}
public class Address{
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="userid") 
    public User getUser() {
       return this.user;
    }
} 
You can have more detail in this post about above entities.

If I want to fetch the user entity and corresponding addresses, I can use below piece of code:
EntityManagerFactory emf 
  = Persistence.createEntityManagerFactory("StateCityService");
EntityManager entityManager= emf.createEntityManager();  
//fetching user entity based on id 
User user = entityManager.find(User.class, userId);  
// Lazy loading of addresses 
Set addresses = user.getAddresses(); 
Now if I change any state of user or address entity and execute merge operation on user entity, then corresponding User's and Address table's column value will be updated.
entityManager.merge(user);
That means, If I remove couple of address items from the set which user entity holds and perform merge operation on user entity, corresponding address rows (which have been removed from the collection defined in user entity) should be deleted based on CascadeType.ALL(add/remove/update). What do you think? You might answer yes. Even I think so.

But not really, CascadeType.REMOVE dose not help you in this scenario.

Achieving same thing in my project I invested couple of ours and found the solution. I had to use OrphanRemoval=true with one to many relationship to achieve this.
public class User{     
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY,
       orphanRemoval=true, mappedBy = "user")
public Set getAddresses() { return this.addresses; } }
'OrphanRemoval=true' Vs 'CascadeType.REMOVE'

The difference between the two settings is in the response to removing child objects from the collection pointed by parent entity.

If orphanRemoval=true is specified the removed address instance is automatically removed. If only cascade=CascadeType.REMOVE is specified no automatic action is taken since removing a relationship is not a remove operation. 

Where 'OrphanRemoval=true' and 'CascadeType.REMOVE' are identical ?

When an User entity object is removed the remove operation is cascaded to the referenced Address entity object. In this case, orphanRemoval=true and cascade=CascadeType.REMOVE are identical.

Use this link to have more detail.