对于 oneToMany 列表 orphanRemoval = true >(带索引)。
这是简化的映射:
public class ParentClass {
[...]
@OneToMany(cascade = ALL, mappedBy = "parent", orphanRemoval = true)
@OnDelete(action = OnDeleteAction.CASCADE)
@Fetch(FetchMode.JOIN)
@OrderColumn(name = "pos", nullable = false)
public List<ChildClass> getChildren() {
return children;
}
}
孩子班:
public class ChildClass {
[...]
@ManyToOne
@JoinColumn(nullable = false, name = "parent_id")
public ParentClass getParent() {
return parent;
}
}
鉴于此映射,以下方案失败:
这是代码
@Transactional
public void test() {
// 1)
ParentClass parent = entityManager.find(ParentClass.class, "some-id");
// 2)
ChildClass child = new ChildClass(parent);
parent.getChildren().add(child);
// 3)
entityManager.find(SomethingElse.class, "2");
// 4)
parent.getChildren().remove(child);
}
在这种情况下,子分配将插入到DB中,而不会在事务结束时删除。
但是,如果我们不执行步骤3),则子分配正确无法在DB中保留
这是一个错误吗?错误的映射? 它有解决方法吗?
答案 0 :(得分:2)
是的,这是一个错误。我打赌你不会使用最新版本的Hibernate(4.3.8),并且它与这个问题有关(如果不是同一个问题):[HHH-9330] orphanRemoval=true does not work in bidirectional relationships (without cascading)即使你使用的是最后一个版本,这个bug仍然存在。如果是这样,请报告,然后在某处报告该错误的URL。解决方法:尝试仅在确定必须持久保存子项时添加子项,或者尝试将子项设置为使子项中的父项为空:
child.setParent(null);
另外,作为另一种解决方法,您可以尝试使用Hibernate会话,而不是使用EntityManager(因为它是在Hibernate&#39; s论坛中编写的)。
答案 1 :(得分:0)
删除子项时需要设置关联的两侧:
child.setParent(null);
parent.getChildren().remove(child);
在您的情况下,孤儿清除是不够的。如果一对多方是单向关联,那么您可以简单地从列表中删除子项,删除将传播到子实体。
当你有双向关联时,你需要让双方同步。这就是为什么你需要在删除时将Child从Parent实体中解除关联。
答案 2 :(得分:0)
JPA注释@PreRemove
可能对您的特定情况有所帮助。尝试将其添加到子实体,以便它可以从父项中删除它自己:
@PreRemove
protected void beforeRemove(){
parent.getChildren().remove(this);
}