C# 从集合中删除项目(NHibernate)

C# 从集合中删除项目(NHibernate),c#,nhibernate,C#,Nhibernate,我有两个实体(父实体和子实体)之间的父子关系 我的父映射如下所示: <class name="Parent" table="Parents"> ... <bag name="Children" cascade="all"> <key column="ParentID"></key> <one-to-many class="Child"></one-to-many> &l

我有两个实体(父实体和子实体)之间的父子关系

我的父映射如下所示:

<class name="Parent" table="Parents">
    ...
    <bag name="Children" cascade="all">
        <key column="ParentID"></key>
        <one-to-many class="Child"></one-to-many>
    </bag>
</class>
子类引用了另一个父类Type。这种关系看起来像

注意:我为上面没有链接的url道歉,我似乎无法通过使用标记的url字符串中的星号

由于这种关系,当调用上述代码时,将生成一个更新查询,该查询将从子表中删除ParentID(设置为null)

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

更新

@斯宾塞溶液

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

@杰米的解决方案

简单而快速的实现,但是我遇到了另一个障碍。我的子实体如下所示:

使用新方法时,NHibernate生成一个update语句,将TypeID和ParentID设置为null,而不是直接删除。如果我在实现过程中遗漏了一些东西,请告诉我,因为这种方法将毫无痛苦地向前推进

@,概述了取消对集合的引用以强制执行单个删除的想法。但是,与上述结果相同,将发出update语句

//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;
//实例化新集合并添加持久化项
列表子项=新列表();
children.AddRange(parent.children);
//从新集合中查找并删除请求的项
var childrenToRemove=children
.其中(c=>c.Type.TypeID==1)
.ToList();
foreach(childrenToRemove中的var c){children.Remove(m);}
parent.Children=null;
//将持久化集合设置为新列表
父母。子女=子女;
解决方案

花了一点时间,但杰米的解决方案通过了一些额外的修改。对于未来的读者,基于以上我的课堂模型:

类型映射-反向=真,级联=全部

父映射-反向=真,级联=全部删除孤立


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

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

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

  • 创建一个包含IList和IList的类,并将其称为CascadeDeleteList或类似的东西
  • 在这个类中创建一个私有的.Net列表,并简单地代理对这个列表的各种方法调用
  • 创建一个名为ICascadeDeleteChild的接口,并给它一个Delete()方法
  • 在CascadeDeleteList的Delete方法下,检查要删除的对象的类型。如果它的类型是ICascadeDeleteChild,那么调用它的Delete方法
  • 更改子类以实现ICASCADELETECHILD接口

  • 我知道这看起来很痛苦,但一旦完成,这些接口应该很容易移植。

    与其公开
    IList
    ,不如通过以下方法控制对集合的访问:

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

    Type.RemoveChild看起来很相似,但您必须小心,不要将其放入调用彼此的RemoveChild方法的无限循环中。

    我相信这可能促使我走上了正确的道路,障碍是:在存储库模式中设置它(即,在这种情况下,child Delete方法将调用自己的存储库方法)并且还能够在不同的会话上下文(即CallSessionContext与WebSessionContext)中使用此功能
    RemoveChild(Child child)
    {
        Children.Remove(child);
        child.Parent = null;
        child.Type.RemoveChild(child);
    }