Thursday, September 04, 2008

NHibernate - Mapping Custom Collections

Came upon this article on mapping custom collections that uses extension methods. I'm not a massive fan of extension methods to be honest and I prefer to use custom collection classes and I thought I'd show how I've seen them mapped in the past.

When I say that I like custom collections I mean classes like this:

public class FooCollection : ReadOnlyCollection<Foo>

I prefer a collection like this over a bog standard IList<Foo> because there is usually a lot of behaviour related to the collection, for example we may have custom rules relating to addition/removal and we'll probably want to ensure the collections contents are valid at all times. One solution would be to use encapsulate collection but I've found that it just results in my aggregate roots and key entities getting bogged down in lots of boring collection work so I prefer to farm out this work to custom collections. Plus if I go for the custom collection approach I can ensure they implement interfaces such as these:

    public interface IReadOnlyCollection<TItem> : IReadOnlyCollection, ...
       bool Contains(TItem toEvaluate);

        IReadOnlyCollection<TItem> FindAll(Specification<TItem> specification);

This sort of interface is very useful because IEnumerable misses some important members and IList is too permissive of change, plus we want to be able to add all sorts of useful helper methods like the FindAll shown.

However I can't directly map my FooCollection, NHibernate is only going to be able to map something basic like an IList. The solution is to map the collection like this:

<component name="FooCollection" access="nosetter.camelcase-underscore">
bag name="_innerList" cascade="all-delete-orphan" access="field" lazy="true">
key column="ContaingClassesID" />
one-to-many class="..." />

This requires a little explaining. We're mapping our custom collection as a component, this seems odd until you look at the way we then map the _innertList within our custom collection. Essentially this _innerList is an IList<Foo> hidden within FooCollection (or more correctly one of its base classes). Since we're mapping an interface NHibernate is happy and the users of our custom collection don't know that we've had to put in this silly _innerList, plus maintaining/using this little internal collection is taken care of by a base class so its all painless. One slight smell is that we're mapping _innerList as a field, not perfect but its not going to keep me up at nights.

Anyway its not a perfect solution but it lets you map custom collections without sacrificing too much.

Share This - Digg It Save to Stumble It! Kick It DZone