关于Java:如何在更新父级上删除子级?

How to delete children on update parent?

我有"父母"和"孩子"hibernate实体。

在"父母"上,我有一个Set<Child>来容纳它的孩子。

当我用新的子代更新父代时,一切正常:子代在" child "表上创建。

但是,当我从父哈希集中删除一个元素并保存时,不会删除数据库中的对应子对象。

这里是:

在父项上(命名为工作流程):

1
2
@OneToMany(orphanRemoval=true, cascade = CascadeType.ALL, mappedBy="workflow", fetch = FetchType.EAGER)
private Set<ActivityDB> activities;

在子上(命名为活动)

1
2
3
4
@ManyToOne
@JoinColumn(name="id_workflow")
@Fetch(FetchMode.JOIN)
private WorkflowDB workflow;

我正在处理会话内的持久实例。没有错误。似乎工作正常,但数据库上的注册仍然存在。

要进行测试,请加载工作流程并执行

1
workflow.activities.remove( activity_index_x )

,然后使用session.update( workflow )保存工作流程。
但是" activity_index_x "仍在数据库中,当我重新加载工作流时,它又恢复了生命。


确保您已阅读有关双向关联链接的手册。

最佳实践包括添加添加/删除子方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class WorkflowDB {

    public void remove (ActivityDB a) {
        if (a != null) {
            this.activities.remove(a);
            a.setWorkflow(null);
        }
    }

    public void add (ActivityDB a) {
        if (a != null) {
            this.activities.add(a);    
            a.setWorkflow(this);
        }
    }

}

但是因为您使用Set作为一对多的一面,所以您需要特别注意equals和hashcode。最好的方法是使用业务密钥来检查相等性和哈希码算法,而永远不要将数据库标识符用于equals / hashcode,尤其是与类似哈希的数据结构(set / map)结合使用时。

双向关联的管理比单向关联更复杂。如果您确实不需要一对多的一面,则可以将其删除并用查询代替它。这样,您只需要管理多对一方面。


这是由于未清除子级对父级引用。由于您已映射了双方(并以此方式进行了配置),因此Hibernate实际上将查看该关系的子端。

解决此问题的最佳方法是,当您从工作流程中删除活动时(以及相反),还要清除活动中的工作流程字段,因此:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Workflow {

  public void remove (Activity a) {
    if (this.activities.remove(a)) {
      a.setWorkflow(null);
    }
  }

  public void add (Activity a) {
    if (this.activities.add(a)) {
      a.setWorkflow(this);
    }
  }
}

主要问题是您要保持关系状态的哪一侧?
您还可以将关系映射到工作流(不使用mapledBy属性,而使用JoinTable批注将列保留在子表上),而仅将父工作流映射为只读(insertable = false,updatable = false)字段。
这样,工作流完全可以控制哪些活动是其中的一部分,并且这些活动仍可以看到它们所属的工作流。

1
2
3
4
5
6
7
8
9
10
11
class Workflow {

    @OneToMany
    @JoinTable(...)
    private Set<Activity> activities
}

class Activity {
    @Column(insertable=false, updatable=false)
    private Workflow workflow
}