【问题标题】:One to Many relationship JPA/Hibernate removing links一对多关系 JPA/Hibernate 删除链接
【发布时间】:2011-08-04 05:50:27
【问题描述】:

我的双向关系设置如下:

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 管理的,它会删除它收到的新集合中不存在的子对象
  • 你能展示一下 setChildren 究竟做了什么吗?我没有看到任何错误。
  • setChildren 是一个简单的访问器方法
  • public void setChildren(Set children) { this.children = children; }

标签: java hibernate gwt jpa


【解决方案1】:

我首先要说的是,直接使用实体管理器的实体是一个非常糟糕的主意。

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]。

【讨论】:

  • 我明白你想说什么,但这仍然是一个非持久层问题。另一方面,在我的例子中,即使是底层的 MySQL 表也包含理想情况下应该删除的链接。
  • 如果这不是问题,您的问题是求解器在关系的 @OneToMany 一侧打开 orphanRemoval。
  • 即使在父母去世后,孩子也应该存在,所以如果我错了请纠正我,但我认为 orphanRemoval=true 不适合我的情况。我要做的就是删除链接。我的理解是 EM 会为我做这件事。猜猜,我将不得不手动完成
【解决方案2】:
// 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:LinkP1-P2 -------------------------------------------------- Id1(PK) Id2(PK) Id1(复合 PK) name1 Name2 Id2(复合PK)

Link 表的Id1Id2 一起是引用Parent1Parent2 表的主键。

【讨论】:

    【解决方案3】:

    这个问题是相关的: JPA CascadeType.ALL does not delete orphans

    【讨论】:

    • 我没有遇到任何异常。表由 EntityManager 在初始化时创建。
    • 删除父级确实删除了子级,所以我不确定它是否与 CascadeType.ALL 不删除孤儿有关
    • 如果我理解正确,取消父母对孩子的引用与删除孩子(em.remove(child))不同。所以这可能是相关的,只是尝试一下。顺便说一句,调用 em.remove(oldChild) 应该可以解决您的问题。
    【解决方案4】:

    ManyToOne 映射控制关系 - 您已将 OneToMany 标记为由子级与其父级的关系映射。这意味着只有在从子端合并时才会获取对关系的更改。因为从父母列表中移除的孩子不再在其中,合并不能级联到它们,并且它们中的任何更改都不会持久化到数据库中。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-05-03
      • 1970-01-01
      • 2022-10-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-12
      相关资源
      最近更新 更多