一对多关系 JPA/休眠删除链接



我有双向关系设置如下:

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 + 实体代理(

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 规范指出

指定为一对一或一对一对多的关联支持使用孤立删除选择。当孤立删除生效时,以下行为适用:

  • 如果实体是目标关系将从关系(通过设置与空的关系或删除关系中的实体集合(,删除操作将应用于正在孤。删除操作为冲洗时应用操作。孤儿移除功能适用于私人"拥有"的实体由其父实体。便携式否则,应用程序不得取决于删除,并且不得重新分配已孤立到的实体其他关系或其他关系尝试保留它。如果实体成为孤儿是一种超然的、新的或删除的实体,语义孤立删除不适用。
  • 如果删除操作应用于托管源实体,删除操作将级联到关系目标符合根据第 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);
}
父1: 父2: 链接P1-P2--------------------------------------------------Id1(PK( Id2(PK( Id1(复合PK(名称1 名称2 Id2(复合PK(

链接表的Id1Id2一起是一个主键,指的是Parent1表和Parent2表。

ManyToOne 映射控制关系 - 您已将 OneToMany 标记为由子项与其父级的关系映射。 这意味着,仅当从子端合并时,才会选取对关系的更改。 由于从父列表中删除的子项不再位于其中,因此无法将合并级联到这些子项,并且它们中的任何更改都不会保存到数据库中。

正如其他人指出的那样,删除孤立项将允许在合并时删除不在列表中的任何子项。 当您想要的只是将关系清空时,这可能是矫枉过正。 在这个疤痕中,您可能可以反转关系,使其归父母所有。 这将确保关系得到更新,但删除的孩子的任何更改仍然不会被拾取。 获取这些更改的唯一方法是将子项添加到合并的新父项中,或单独合并它们。 如果它们可以在没有父级的情况下存在,则直接对它们调用持久/合并是更好的选择。

这个问题是相关的:JPA CascadeType.ALL 不删除孤立项

最新更新