一对多关系JPA/Hibernate删除链接

hel*_*llo 2 java gwt hibernate 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();

        }
    }

}
Run Code Online (Sandbox Code Playgroud)

在我的客户端,我有以下代码(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();
Run Code Online (Sandbox Code Playgroud)

此代码仅适用于添加新子项.即使父类接收到空子集,从父项中删除子项也不起作用.JOIN表中的链接不会被删除.

你能告诉我哪里遗失了什么吗?

谢谢!

Edw*_*rzo 6

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

EntityManager.merge()方法返回实际的合并实例,这意味着在您的代码中,当您发布时

em.merge(this)
Run Code Online (Sandbox Code Playgroud)

您不能保证合并的实例不再对应于"this",从那时起您可能会看到各种逻辑问题.

如果您认为这不是一件大事,那么您的问题应该通过在关系的OneToMany端启用孤儿删除来解决,前提是孩子不会在其他关系中的其他地方使用.否则,您将不得不手动进行合并.

@OneToMany(mappedBy="parent", cascade=CascadeType.ALL, orphanRemoval=true)
Set<Child> childrens = new HashSet<Child>();
Run Code Online (Sandbox Code Playgroud)

JPA 2.0规范指出了这一点

指定为OneToOne或OneToMany的关联支持使用orphanRemoval选项.当orphanRemoval生效时,以下行为适用:

  • 如果从关系中删除作为关系目标的实体(通过将关系设置为null或从关系集合中删除实体),则删除操作将应用于要孤立的实体.在刷新操作时应用移除操作.orphanRemoval功能适用于由其父实体私有"拥有"的实体.否则,便携式应用程序必须不依赖于特定的删除顺序,并且不得将已经孤立的实体重新分配给另一个关系或以其他方式尝试保留它.如果孤立的实体是分离的,新的或已删除的实体,则orphanRemoval的语义不适用.
  • 如果将删除操作应用于托管源实体,则删除操作将根据第3.2.3节的规则级联到关系目标(因此没有必要为关系指定cascade = REMOVE)[ 20.