There is more to it though.Here is PersistentBag implementation. Ask if you have more questions as it took me a while to figure this whole thing out.
Code:
public class PersistentBag<T> : PersistentGenericBag<T>, .IBag<T>
{
public PersistentBag(ISessionImplementor session) : base(session) { }
public PersistentBag(ISessionImplementor session, IList<T> coll) : base(session, coll) { }
#region Events
public event EventHandler<CollectionChangedEventArgs<T>> BagChanged;
#endregion
#region IBag<T> interface
here comes your implementation of the interface
just two methods to see how to add and remove
public new void Add(T item)
{
//Console.WriteLine("Bag.Add() start");
if (item == null)
{
throw new ArgumentNullException("item", "item can't be null");
}
this.PerformAdd(item);
//Console.WriteLine("Bag.Add() end");
}
public new bool Remove(T item)
{
bool removed = false;
int index = this.IndexOf(item);
if (index >= 0)
{
removed = base.Remove(item);
if (!removed)
{
throw new ApplicationException("The remove failed, as List<T>.Remove returned false");
}
}
this.OnBagChanged(item, CollectionChangeType.ItemRemoved, index);
this.OnCollectionChanged(NotifyCollectionChangedAction.Remove, item, index);
return removed;
}
#end region
#region Helper Methods
protected int PerformAdd(T item)
{
base.Add(item);
int idx = this.Count - 1;
OnBagChanged(item, CollectionChangeType.ItemAdded, idx);
OnCollectionChanged(NotifyCollectionChangedAction.Add, item, idx);
// Console.WriteLine("EntityBag.PerformAdd() end");
return idx;
}
/// <summary>
/// Raises the <see cref="BagChanged"/> event to indicate that item(s)
/// have been added to, or removed from, this collection.
/// </summary>
protected virtual void OnBagChanged(T involvedItem, CollectionChangeType action, int index)
{
if (BagChanged != null)
{
BagChanged(this, new CollectionChangedEventArgs<T>(involvedItem, action, index));
}
}
#region INotifyCollectionChanged
public event NotifyCollectionChangedEventHandler CollectionChanged;
/// <summary>
/// Raises the <see cref="CollectionChanged"/> event to indicate that item(s)
/// have been added to, or removed from, this collection.
/// </summary>
protected virtual void OnCollectionChanged(NotifyCollectionChangedAction action, object changedItem, int index)
{
if (CollectionChanged != null)
CollectionChanged(this, new NotifyCollectionChangedEventArgs(action, changedItem, index));
}
#endregion
You will have to implement custom type like this
Code:
/// <summary>
/// The NHibernate type for a generic bag collection that fires events
/// when item(s) have been added to or removed from the collection.
/// </summary>
/// <typeparam name="T">The type of items in the bag</typeparam>
public class PersistentBagType<T> : IUserCollectionType
{
#region IUserCollectionType Members
public bool Contains(object collection, object entity)
{
return ((IList<T>)collection).Contains((T)entity);
}
public IEnumerable GetElements(object collection)
{
return (IEnumerable)collection;
}
public object IndexOf(object collection, object entity)
{
return ((IList<T>)collection).IndexOf((T)entity);
}
public object Instantiate(int anticipatedSize)
{
//TODO: check where is this size comming from, NH does not seem to use it at all
return new Bag<T>();
}
public IPersistentCollection Instantiate(ISessionImplementor session, ICollectionPersister persister)
{
return new PersistentBag<T>(session);
}
public object ReplaceElements(object original, object target, ICollectionPersister persister, object owner,
IDictionary copyCache, ISessionImplementor session)
{
IList<T> result = (IList<T>)target;
result.Clear();
foreach (object item in ((IEnumerable)original))
result.Add((T)item);
return result;
}
public IPersistentCollection Wrap(ISessionImplementor session, object collection)
{
return new PersistentBag<T>(session, (IBag<T>)collection);
}
#endregion
}
and then in mapping files you will have to map it like this
Code:
<!-- m 4 -->
<bag name="lineItems" inverse="true" lazy="true" table="LINE_ITEM" cascade="all"
collection-type="MyCompany.NHibernate.Collections.PersistentBagType`1[
[MyCompany.AR200.Core.billing.LineItem, MyCompany.AR200.Core]], MyCompany.NHibernate">
<key column="INVOICE_VEOID"/>
<one-to-many class="MyCompany.AR200.Core.billing.LineItem"/>
</bag>