代码之家  ›  专栏  ›  技术社区  ›  Alexis Abril

从集合中移除项目(nhibernate)

  •  5
  • Alexis Abril  · 技术社区  · 16 年前

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

    我的父映射如下:

    <class name=“parent”table=“parents”>
    …
    <bag name=“children”cascade=“all”>
    <key column=“parentid”></key>
    <one to many class=“child”></one to many>
    和/袋;
    & lt;/类& gt;
    

    我想执行以下操作:

    someparent.children.remove(somechild);
    < /代码> 
    
    

    子类引用了另一个父类,类型。这段关系看起来像

    注意:对于上面的非链接URL,我深表歉意,我似乎无法通过使用标记的URL字符串中的星号。

    由于这种关系,当调用上述代码而不是删除查询时,将生成一个更新查询,它从子表中删除parentID(设置为空)。

    当从parent.children集合中删除子记录时,是否可以强制nhibernate完全删除该子记录?

    更新

    @斯宾塞的解决方案

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

    @杰米的解决方案

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

    使用新方法时,nhibernate生成一个update语句,将typeid和parentid设置为空,而不是直接删除。如果我错过了实现中的某些内容,请告诉我,因为使用此方法可以轻松地向前推进。

    @The one-shot delete solution described here,outlines an idea dereferenceing the collection to force a single delete.但是,与上面的结果相同,会发出更新语句。

    实例化新集合并添加持久化项 list<child>children=新列表<child>(); children.addrange(parent.children); //从新集合中查找和删除请求的项 var childrentoremove=儿童 。其中(c=>c.type.typeid==1) 。 foreach(childrentoremove中的var c)children.remove(m); parent.children=空; //将持久化集合设置为新列表 parent.children=孩子; < /代码>

    解决方案

    经过一些挖掘,杰米的解决方案得到了一些额外的修改。对于未来的读者,基于我上面的类模型:

    类型映射-反转=真,层叠=全部

    父映射-反转=真,层叠=全部删除孤立

    移除Jamie解决方案工作中描述的方法。这确实会为每个孤立项生成一条DELETE语句,因此将来有可能进行优化,但是最终结果是成功的。

    我想执行以下操作:

    someParent.Children.Remove(someChild);
    

    子类引用了另一个父类,类型。这段关系看起来像

    relation diagram

    注意:对于上面的非链接URL,我深表歉意,我似乎无法通过使用标记的URL字符串中的星号。

    由于这种关系,当调用上述代码而不是删除查询时,将生成一个更新查询,它从子表中删除parentID(设置为空)。

    当从parent.children集合中删除子记录时,是否可以强制nhibernate完全删除该子记录?

    更新

    @斯宾塞的解决方案

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

    @杰米的解决方案

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

    使用新方法时,nhibernate生成一个update语句,将typeid和parentid设置为空,而不是直接删除。如果我在实现中遗漏了一些东西,请告诉我,因为这个方法可以轻松地向前推进。

    @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解决方案工作中描述的方法。这确实会为每个孤立项生成一条DELETE语句,因此将来有可能进行优化,但是最终结果是成功的。

    2 回复  |  直到 9 年前
        1
  •  1
  •   Jamie Ide    16 年前

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

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

    type.removechild看起来很相似,但必须注意不要将其放入调用彼此的removechild方法的无限循环中。

        2
  •  0
  •   Spencer Ruport    16 年前

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

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

    1. 创建一个包含ilist和ilist的类,并将其命名为cascadeDeleteList或这些行中的某个类。
    2. 在这个类中创建一个私有的.NET列表,并简单地将各种方法调用代理到这个列表中。
    3. 创建一个名为icascadedeletechild的接口,并给它一个方法delete()。
    4. 在级联删除列表的删除方法下,检查要删除的对象的类型。如果它的类型为icascadedeletechild,则调用它的delete方法。
    5. 更改子类以实现icascadedeletechild接口。

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