一对多关系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 + 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标记为由子对象与其父对象的关系映射。这意味着仅当从子侧合并时才拾取对关系的更改。由于从父级列表中删除的子级不再存在,因此无法将合并级联到它们,并且对它们的任何更改都永远不会持久化到数据库中。 正如其他人指出的那样,通过删除孤儿可以使列表中未包含的所有子项在合并时被删除。当您想要的只是消除关系时,这可能会过大。在这种伤痕中,您可能可以反转关系,使其由父级拥有。这样可以确保关系得到更新,但是删除的子项中的任何更改仍然不会被拾取。获取这些更改的唯一方法是将子级添加到要合并的新父级中,或者独立合并它们。如果它们可以在没有父母的情况下存在,则直接对其调用持久/合并是更好的选择。     

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...