如何在更新父级上删除子项?

时间:2014-07-11 19:17:58

标签: java hibernate jpa orm hibernate-mapping

我有父母"和"孩子"休眠实体。

On&#34; Parent&#34;我有Set<Child>来容纳它的孩子。

当我用新孩子更新父母时,一切正常:儿童是在&#34;孩子&#34;表

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

这是:

关于父母(名为工作流程):

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

On Child(名为Activity)

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

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

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

workflow.activities.remove( activity_index_x )

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

2 个答案:

答案 0 :(得分:1)

这是由未清除子到父引用引起的。由于你映射了两面(并以这种方式配置),Hibernate实际上会查看关系的子端。

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

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);
    }
  }
}

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

class Workflow {

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

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

答案 1 :(得分:1)

请务必查看有关bidirectional association links

的手册

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

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 and hashcode。最好的方法是使用业务键来检查相等性和哈希码算法,并且永远不要使用equals / hashcode的数据库标识符,尤其是与类似哈希的数据结构(set / map)一起使用。

双向关联管理比单向关联更复杂。如果您确实不需要一对多方,则可以将其删除并替换为查询。这样你就必须只管理多对一方。