NHibernate:在集合上调用.RemoveAll

时间:2012-01-27 11:23:02

标签: c# nhibernate fluent-nhibernate

我遇到一个问题,即在通过NHibernate检索集合时无法使用.RemoveAll

我有一个名为Order的实体,我通过NHibernate持续存在。

Order有很多OrderItems。这是我对这种关系的映射:

mapping.HasMany(o => o.Items)
                   .Cascade.AllDeleteOrphan()
                   .AsList()
                   .Inverse();

在我的域中看起来像这样:

public virtual IList<OrderItem> Items { get; set; }

据我了解,我必须使用IList,因为NHibernate拥有自己的List实现。

现在,我想在我的Order课程中使用此方法从我的Order删除一个项目:

public virtual void RemoveItem(string variantSku)
{
    items.RemoveAll(x => x.Variant.VariantSku == variantSku);
}

它不起作用,因为IList没有这种方法。

我试过了:

items.ToList().RemoveAll(x => x.Variant.VariantSku == variantSku);

但这似乎不起作用。我意识到items.ToList()实际上创建了原始列表的副本,所以我想我可以尝试:

var itemsList = items.ToList();
itemsList.RemoveAll(...)

但是它仍然通过NHibernate持续存在吗?

我的问题:我是否可以在此上下文中使用.RemoveAll,还是应该考虑以不同的方式删除项目?

2 个答案:

答案 0 :(得分:4)

您将集合映射为关系的反面,因此除了从集合中删除项目之外,您还必须在OrderItem端取消对Order的引用。因此,RemoveAll方法或扩展方法将无法完成这项工作。

我会这样处理:

public virtual void RemoveItem(string variantSku)
{
    var itemsToRemove = items.Where(x => x.Variant.VariantSku == variantSku).ToArray();
    foreach(var item in itemsToRemove)
    {
       item.Order = null;
       items.Remove(item);
    }
}

我还建议使用set而不是bag mapping。

答案 1 :(得分:3)

您始终可以创建自己的RemoveAll扩展程序:

public static void RemoveAll<T>(this IList<T> source, Predicate<T> predicate)
{
    // TODO: Argument non-nullity validation

    // Optimization
    List<T> list = source as List<T>
    if (list != null)
    {
        list.RemoveAll(predicate);
        return;
    }

    // Slow way
    for (int i = source.Count - 1; i >= 0; i--)
    {
        if (predicate(source[i]))
        {
            source.RemoveAt(i);
        }
    }
}

我希望期待 NHibernate关心集合本身 - 只是从List<T>删除一个项目并不是NHibernate可以“注意到的”。

当然,如果您不希望NHibernate关心您的工作 - 如果您的更改只是意味着是本地的 - 那么您的最后一段代码就可以了。