我遇到一个问题,即在通过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
,还是应该考虑以不同的方式删除项目?
答案 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关心您的工作 - 如果您的更改只是意味着是本地的 - 那么您的最后一段代码就可以了。