问题描述
|
我有如下双向关系设置:
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表中的链接不会删除。
你能告诉我我在想什么吗?
谢谢!
解决方法
首先,我要说的是一个糟糕的主意,即实体是直接使用实体管理器的实体。
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生效时,将发生以下行为:
如果是作为目标的实体
关系从
关系(通过设置
与null的关系或删除
关系中的实体
集合),执行删除操作
将应用于
成为孤儿。删除操作是
在冲洗时使用
操作。孤儿搬迁
功能旨在
私人拥有的实体
由其父实体。随身携带
申请不得
取决于特定的顺序
搬迁,且不得重新分配
成为孤儿的实体
其他关系或其他
尝试坚持下去。如果实体
成为孤儿是一个超脱的,新的或
删除的实体,的语义
orphanRemoval不适用。
如果将删除操作应用于
受管源实体,删除
操作将级联到
关系目标符合
根据3.2.3节的规则,(和
因此没有必要指定
级联=删除
关系)[20]。
,// 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(复合PK)
name1 Name2 Id2(复合PK)
Link表中的Id1
和Id2
是一起引用Parent1
和Parent2
表的主键。
,这个问题有关:
JPA CascadeType.ALL不会删除孤儿
,ManyToOne映射控制关系-您已将OneToMany标记为由子对象与其父对象的关系映射。这意味着仅当从子侧合并时才拾取对关系的更改。由于从父级列表中删除的子级不再存在,因此无法将合并级联到它们,并且对它们的任何更改都永远不会持久化到数据库中。
正如其他人指出的那样,通过删除孤儿可以使列表中未包含的所有子项在合并时被删除。当您想要的只是消除关系时,这可能会过大。在这种伤痕中,您可能可以反转关系,使其由父级拥有。这样可以确保关系得到更新,但是删除的子项中的任何更改仍然不会被拾取。获取这些更改的唯一方法是将子级添加到要合并的新父级中,或者独立合并它们。如果它们可以在没有父母的情况下存在,则直接对其调用持久/合并是更好的选择。