这里有一个小问题:
我有两个实体类,比方说
class Parent {
Set<Child> children;
}
class Child {
SomethingElse reference;
}
现在映射本质上是:
<class name="Parent" lazy="false">
<set name="children" lazy="false" cascade="all-delete-orphan">
<key column="parent_id"/>
<one-to-many class="Child"/>
</set>
</class>
(我在这里省略了 id 映射和字段,我使用常规生成的 id)
我基本上需要保持一个干净的数据库,就像当我从父列表中删除元素然后提交父时一样,需要删除相应删除的子数据库条目。Child 实例引用了我以后需要删除的其他实体,因此如果子实例保留在数据库中,我将无法删除那些引用的对象。
到目前为止我发现了什么:如果我要保持 hibernate 的 PersistentCollection 包装器就位,我在下面尝试的任何事情都应该有效。问题是,我的数据库对象来自几层框架,其中包括一个 UI 框架,它使用 bean 属性抽象来调用 setter,以及一个来回克隆和序列化对象的网络通信层。这两个层都在内部替换了集合实例,因此删除了这些 PersistentCollection 包装器。重写这些以不这样做不是一种选择。
也就是说,我尝试过的 8 件事没有奏效:
1) 将关系配置为 cascade="all",使用 session.update(parent)。
2) 将关系配置为 cascade="all-delete-orphan",使用 session.update(parent)。
3) 将关系配置为 cascade="all" 并使用 session.merge(parent)
所有这些都会导致休眠执行“UPDATE CHILD SET parent.id = null WHERE parent.id = ...”。这在重新加载父实例时成功地从父列表中删除了子实例,但子实例保留在数据库中并阻止我删除其他引用的实体。
4-6) 使用配置 1-3,同时将父键列定义为非空
这导致休眠不做任何事情。我在另一篇文章中读到,使键列非空会导致删除。听起来可能,因为更新为 null 不再是一种选择,但不起作用。如果我从集合中删除孩子,提交更改并从数据库重新加载实例,孩子会重新出现。
7+8) 父键可空或非空无关紧要,但将关系配置为 cascade=all-delete-orphans 并使用 session.merge(parent)
由于删除了 PersistentCollection 包装器,这会导致 hibernate 抛出异常“具有 cascade="all-delete-orphan" 的集合不再被拥有的实体实例引用”。
为了解决我的问题,我唯一需要的是休眠来执行选项 1-3 中的查询作为删除而不是更新。我希望我只是无法找到以在没有 PersistentCollection 包装器的情况下删除这些映射的方式来配置映射的选项,但在我看来,目前似乎没有这样的选项。有谁知道是否有办法配置这个?
/编辑:为了澄清,我想要发生的事情的例子:
Parent parent = new Parent();
parent.setChildren(new HashSet<Child>(Arrays.asList(new Child()))));
session.insert(parent)
// this correctly results in (approximately):
// SQL> INSERT INTO PARENT ...
// SQL> INSERT INTO CHILD ...
parent.setChildren(new HashSet<Child>()); // using .clear() is not an option.
session.update(parent);
// this results in:
// SQL> UPDATE CHILD set parent_id = null WHERE parent_id = ${id.of.parent}
// but i need this to result in:
// SQL> DELETE FROM CHILD WHERE parent_id = ${id.of.parent}