我有两个实体连接了双向OneToMany / ManyToOne关系。
@Entity
class One {
@OneToMany(mappedBy = "one", orphanRemoval = true, fetch = FetchType.EAGER)
private Set<Many> manies;
// ...
}
@Entity
class Many {
@ManyToOne
@JoinColumn(name = "one_id", nullable = false)
private One one;
// ...
}
如果我要删除Many
个实例,请将其从One
manies
Set
中删除,然后将其从数据库中删除。如果我采用相同的One
实例并再次保存(因为我改变了任何内容,它不必与关系相关),我得到一个例外:
javax.persistence.EntityNotFoundException:无法找到id为12345的test.Many
ID(在此示例中为12345)是刚刚删除的实体的ID。请注意,删除实体12345成功:事务成功提交,并从数据库中删除该行。
使用Spring Data存储库添加和删除实例。删除看起来或多或少像这样:
one.getManies().remove(manyToRemove);
oneDao.save(one);
manyDao.delete(manyToRemove);
我调试了一点,发现Set
是一个Hibernate PersistentSet
,其中包含一个字段storedSnapshot
。这又是另一个Set
仍然引用被删除的实体。我不知道为什么这个引用没有从快照中删除但我怀疑这是问题:我认为Hibernate试图第二次删除该实体,因为它在快照中但不在实际集合中。我搜索了很长一段时间,但我没有遇到类似问题的其他人。
我使用Hibernate 4.2.2和Spring Data 1.6.0。
我在做一些内在错误的事情吗?我该如何解决这个问题?
答案 0 :(得分:4)
我遇到了同样的问题。
解决方法是替换整个集合。
Set<Many> maniesBkp = one.getManies(); // Instance of PersistentSet
maniesBkp.remove(manyToRemove);
Set<Many> manies = new HashSet<Many>();
manies.addAll(maniesBkp);
one.setManies(manies);
...
manyDao.delete(manyToRemove);
...
oneDao.save(one);
答案 1 :(得分:2)
由于您的@OneToMany
关系有orphanRemoval = true
,您不必从数据库中显式删除子元素 - 只需将其从集合中删除并保存父元素。
答案 2 :(得分:0)
尝试添加CascadeType.REMOVE和orphanRemoval
@OneToMany(mappedBy = "one", orphanRemoval = true, fetch = FetchType.EAGER, cascade = CascadeType.REMOVE, orphanRemoval = true)
比执行删除
one.getManies().remove(manyToRemove);
oneDao.save(one);
编辑: 我创建了POC,查看UserRepositoryIntegrationTest.departmentTestCase(code)