在休眠级联删除的问题

问题描述:

这个问题已被问过很多次,但我没有看到一个令人满意的答案,因此,我再次问它。在休眠级联删除的问题

想象一下以下情况:

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; 

    ... 
} 

所有我想要的是删除用户。从逻辑上讲,会假设所有连接用户和位置的相关“关注者”条目都将被删除。如果我删除一个位置条目,则相同的假设应该保持在这种状态。

实际发生的事情是,Hibernate试图更新(?!?)拥有关注者的表,并且因为相关实体(用户或位置)已被发送删除,所以尝试设置外键followerId为null。这会引发异常,并破坏所有后续操作。

我得到的错误: 服务器出现未处理的故障。无法执行JDBC批处理更新; SQL [update locationstofollowers set followerId = null where followerId =?];约束[null];嵌套异常是org.hibernate.exception.ConstraintViolationException:无法执行JDBC批量更新

P.S.我听说有另一个级联选项DELETE_ORPHAN。这似乎已被废弃,即使我也尝试过,效果也是一样的。

+0

非常好的问题。可悲的是,在这方面没有多少讨论。 – pavanlimo 2011-08-03 12:53:59

既然你已经做了双向映射,你必须从两个地方删除对象。这应该工作:

user.followedLocations.remove(aLocation); 
session.update(user); 
session.delete(aLocation); 
+0

这将创建耦合不会吧。 – xantrus 2011-05-15 17:17:55

+1

不是不行,映射已经以双向的方式完成,这里的问题是位置中的用户对象已被映射为非空值..这是造成问题的原因......问题也可以通过取消设置该字段不为空... – 2011-05-16 15:40:20

+0

工程很好。谢谢Anantha!我希望@xantrus接受这个答案并将其关闭。 – pavanlimo 2011-08-04 04:01:13

应设置@JoinColumn(name = “followerId”,插入=假,可更新= FALSE)