我的双向关系设置如下:
class Child{
@ManyToOne
@JoinTable(name = "CHILDREN_WITH_PARENT",
joinColumns = {@JoinColumn(name = "CHILD_ID")},
inverseJoinColumns = {@JoinColumn(name = "PARENT_ID")}
)
private Parent parent;
}
class Parent{
@OneToMany(mappedBy="parent", cascade=CascadeType.ALL)
Set<Child> childrens = new HashSet<Child>();
public void persistOrMerge() {
EntityManager em = entityManager();
em.getTransaction().begin();
try {
if (em.contains(this))
return;
if (id == null || id == 0) {
this.setCreatedDate(new Date());
em.persist(this);
} else {
Parent prev = em.find(Parent.class, this.id);
if (prev == null) {
em.persist(this);
} else{
this.setCreatedDate(new Date());
em.merge(this);
}
}
em.flush();
em.getTransaction().commit();
} finally {
em.close();
}
}
}
在我的客户端,我有以下代码(GWT + EntityProxy)
Set<ChildProxy> children = new HashSet<ChildProxy>();
if(childIsNew)
child = request.create(Children.class)
else
child = request.edit(oldChild)
children.add(child);
//If children are deleted, they are not contained in the set
//we are sending back to server
parent.setChildren(children)
parent.persistOrMerge();
此代码仅适用于添加新子代。即使父类接收到空子集,从父项中删除子项也不起作用。 JOIN表中的链接不会被删除。
你能告诉我遗失的地方吗?
谢谢!
答案 0 :(得分:6)
我首先要说的是,实体是直接使用实体管理器的实体是一个非常糟糕的主意。
EntityManager.merge()方法返回实际的合并实例,这意味着在您的代码中,当您发出
时em.merge(this)
您无法保证合并后的实例不再与“this”对应,从那时起您可能会看到各种逻辑问题。
如果您认为这不是什么大问题,那么您的问题应该通过在关系的OneToMany端启用孤儿删除来解决,前提是孩子不会在其他关系中的其他任何地方使用。否则你将不得不手动合并。
@OneToMany(mappedBy="parent", cascade=CascadeType.ALL, orphanRemoval=true)
Set<Child> childrens = new HashSet<Child>();
JPA 2.0规范声明
指定为OneToOne或OneToMany的关联支持使用orphanRemoval 选项。当orphanRemoval生效时,以下行为适用:
答案 1 :(得分:1)
// In the entity class of Parent1 write a method to unlink parent2
public void unLinkParent2(Parent2 parent2)
{
//remove columns from the link table, pertaining to the parent2
getParent2Collection().remove(parent2);
// using the parent2 object remove 'this' parent1 entity link columns
parent2.getParent1Collection().remove(this);
}
Parent1: Parent2: LinkP1-P2 -------------------------------------------------- Id1(PK) Id2(PK) Id1 (composite PK) name1 Name2 Id2 (composite PK)Link表的
Id1
和Id2
是一个引用Parent1
和Parent2
表的主键。
答案 2 :(得分:0)
答案 3 :(得分:0)
ManyToOne映射控制关系 - 您已将OneToMany标记为子项与其父项的关系所映射。这意味着只有在从子端合并时才会获取对关系的更改。由于从父列表中删除的子项不再包含在其中,因此无法将merge级联到它们,并且它们中的任何更改都不会持久保存到数据库中。
正如其他人所指出的,孤儿删除将允许在合并时删除列表中没有的任何子项。当你想要的只是关系被淘汰时,这可能是过度的。在这个疤痕中,你可以扭转这种关系,使它由父母拥有。这将确保关系得到更新,但删除的子项中的任何更改仍然无法获取。获取这些更改的唯一方法是将子项添加到合并的新父项,或者单独合并它们。如果它们可以在没有父项的情况下存在,则直接调用它们的persist / merge是更好的选择。