Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problems with cascading deletion in Hibernate

This question has been asked numerous times before, yet I haven't seen a satisfactory answer since, thus I am asking it again.

Imagine the following situation:

public class User {
    ...

    @Cascade(value= {CascadeType.DELETE})
    @OneToMany(fetch = FetchType.LAZY)
    @JoinColumn(name="followerId")
    public List<LocationFollower> followedLocations;

    ...
}

public class LocationFollower {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id", nullable = false)
    public Long id;
    
    @ManyToOne
    @JoinColumn(name="locationId")
    public Location followedLocation;
    
    @ManyToOne
    @JoinColumn(name="followerId")
    public User follower;
    
    @Column(name = "followerSince")
    public Timestamp followerSince;
}

public class Location {
    ...

    @Cascade(value = {CascadeType.DELETE})
    @OneToMany(fetch= FetchType.LAZY)
    @JoinColumn(name="locationId")
    public List<LocationFollower> followers;

    ...
}

All I wanted was to delete a user. Logically, one will assume all related "follower" entries connecting User and Location will be deleted. The same assumption should stay in power if I delete a Location entry.

What happens actually is that Hibernate tries to update (?!?) the table that holds the followers, and since the related entity (User or Location) has been sent for deletion, tries to set a foreign key, for instance, followed with null. This throws an exception and burst all the succeeding operations.

The error I get: There was an unhandled failure on the server. Could not execute JDBC batch update; SQL [update locationstofollowers set followerId=null where followerId=?]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update

P.S. I hear that there was another cascade option DELETE_ORPHAN. This seems to be deprecated, and even though I tried it as well, the effect was the same.

like image 610
xantrus Avatar asked May 15 '11 15:05

xantrus


2 Answers

Since you have made a bi-directional mapping, you have to remove the object from both places. This should work:

user.followedLocations.remove(aLocation);
session.update(user);
session.delete(aLocation);
like image 140
Anantha Sharma Avatar answered Sep 28 '22 03:09

Anantha Sharma


You should set @JoinColumn(name="followerId", insertable = false, updatable = false)

like image 36
MountainFlying Avatar answered Sep 28 '22 04:09

MountainFlying