Reputation: 4433
I have a problem with not being able to use .RemoveAll
when retrieving a collection via NHibernate.
I have an entity called Order
that I persist via NHibernate.
Order
has many OrderItems
. Here is my mapping for this relationship:
mapping.HasMany(o => o.Items)
.Cascade.AllDeleteOrphan()
.AsList()
.Inverse();
In my domain that look like this:
public virtual IList<OrderItem> Items { get; set; }
As I understand it, I have to use IList
because NHibernate has it's own implementation of List.
Now I want to remove an item from my Order
using this method on in my Order
class:
public virtual void RemoveItem(string variantSku)
{
items.RemoveAll(x => x.Variant.VariantSku == variantSku);
}
It doesn't work, because IList
does not have this method.
I tried:
items.ToList().RemoveAll(x => x.Variant.VariantSku == variantSku);
But that doesn't seem to work. I realise the items.ToList()
actually creates a copy of the original list, so I guess I could try:
var itemsList = items.ToList();
itemsList.RemoveAll(...)
But then does it still persist via NHibernate?
My question: can I actually use .RemoveAll
in this context or should I be thinking about a different way to remove an item?
Upvotes: 3
Views: 1695
Reputation: 49251
You have the collection mapped as the inverse side of the relationship, so in addition to removing the item from the collection you have to nullify the reference to the Order on the OrderItem side. Therefore the RemoveAll method, or the extension method, won't do the job.
I would handle it like this:
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);
}
}
I also suggest using set instead of bag mapping.
Upvotes: 4
Reputation: 1500015
You could always create your own RemoveAll
extension method:
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);
}
}
}
I would expect NHibernate to care about the collection itself - just removing an item from a List<T>
isn't something that NHibernate can "notice".
Of course, if you didn't want NHibernate to care about what you do - if your changes were only meant to be local - then your final piece of code would be fine.
Upvotes: 3