从集合中删除项目(NHibernate)

时间:2010-02-16 22:04:50

标签: c# nhibernate

我在两个实体(父母和子女)之间有父子关系。

我的父映射如下:

<class name="Parent" table="Parents">
    ...
    <bag name="Children" cascade="all">
        <key column="ParentID"></key>
        <one-to-many class="Child"></one-to-many>
    </bag>
</class>

我想执行以下操作:

someParent.Children.Remove(someChild);

Child类具有对另一个父类Type的引用。这种关系看起来像是

relation diagram

注意:我为上面的非链接网址道歉,我似乎无法使用标记 来覆盖网址字符串中的星号

由于这种关系,当调用上面的代码而不是DELETE查询时,会生成一个UPDATE查询,该查询从Child表中删除ParentID(设置为null)。

从Parent.Children集合中删除时,是否可以强制NHibernate完全删除子记录?

更新

@ Spencer的解决方案

非常有吸引力的解决方案,因为这可以在未来的课程中实施。但是,由于在存储库模式中处理会话的方式(在我的特定情况下),这几乎是不可能的,因为我们必须根据应用程序传递会话类型(CallSessionContext / WebSessionContext)。

@ Jamie的解决方案

简单快捷地实施,但是我遇到了另一个障碍。我的子实体看起来如下: entity object

使用新方法时,NHibernate会生成一个更新语句,将TypeID和ParentID设置为null,而不是单个删除。如果我在实施过程中遗漏了一些内容,请告诉我,因为这种方法可以毫不费力地继续前进。

@ The One-Shot-Delete solution described here,概述了取消引用该集合以强制执行单个删除的想法。与上述结果相同,会发布更新声明。

//Instantiate new collection and add persisted items
List<Child> children = new List<Child>();
children.AddRange(parent.Children);

//Find and remove requested items from new collection
var childrenToRemove = children
    .Where(c => c.Type.TypeID == 1)
    .ToList();

foreach (var c in childrenToRemove) { children.Remove(m); }
parent.Children = null;

//Set persisted collection to new list
parent.Children = Children;

解决方案

进行了一些挖掘,但Jamie的解决方案经过了一些额外的修改。对于未来的读者,基于我上面的班级模型:

类型映射 - Inverse = true,Cascade = all

父映射 - Inverse = true,Cascade = all-delete-orphan

删除Jamie解决方案中描述的方法。这确实会为每个孤立项生成一个删除语句,因此将来可以进行调整,但最终结果是成功的。

2 个答案:

答案 0 :(得分:1)

不是公开IList<Child>,而是通过以下方法控制对集合的访问:

RemoveChild(Child child)
{
    Children.Remove(child);
    child.Parent = null;
    child.Type.RemoveChild(child);
}

Type.RemoveChild看起来很相似,但你必须小心不要把它放到一个无限循环中调用彼此的RemoveChild方法。

答案 1 :(得分:0)

我不认为这是完全可能的,因为Hibernate无法知道该记录是否已被孤立。它可以检查是否有任何其他类与子类相关,但是它会假设它知道整个数据库结构可能不是这种情况。

然而,你并没有完全失去运气。通过将IList接口与您创建的自定义ICascadeDeleteChild接口结合使用,您可以提出一个相当无缝的解决方案。以下是基本步骤。

  1. 创建一个inheirits IList和IList&lt;&gt;的类。并称之为CascadeDeleteList或类似的东西。
  2. 在此类中创建一个私有.Net列表,并简单地代理对此List的各种方法调用。
  3. 创建一个名为ICascadeDeleteChild的接口,并为其指定一个方法Delete()
  4. 在CascadeDeleteList的Delete方法下,检查要删除的对象的类型。如果它是ICascadeDeleteChild类型,则调用它的Delete方法。
  5. 更改您的Child类以实现ICascadeDeleteChild接口。
  6. 我知道这似乎很痛苦但是一旦完成这些接口应该很容易移植。