I also implemented something similar for a Point3D struct. As cdmdotnet said you basically want to implement and IUserType that will pack/unpack Features into a single string via the NullSafeSet/NullSafeGet methods.
You may also need to implement the Equals() method, which is a little subtle. The reason why is best illustrated by an example:
Product p = session.Load(...);
p.Features.Add("extra feature");
session.Save(p);
The thing is, NHibernate upon hydration stores a reference to p.Features, and compares it to the value of p.Features upon a save request. For immutable property types this is fine, but in the above example, these references are identical, so the effective comparison is
var x = p.Features;
var changed = Equals(x, x);
Obviously a standard implementation of this will always return false.
How should one deal with this? I have no idea what the best practice is, but solutions are:
Make IUserType.Equals(object x, object y) always return false. This will force the packed string to be rebuilt and a database call to be made every single time the Product is saved, irregardless of whether Product has been semantically changed or not. Whether or not this is an issue depends on any number of factors (size/count of Feature objects, whether Product objects are saved when not changed, how many Product objects you have etc).
Make Features an IList and implement a ChangeAwareList<T> : IList<T>
which is able to track changes (or keep a copy of its original) aware. Implement IUserType.Equals(object x, object y) to check if x/y are ChangeAwareList and implement the necessary logic to see if the list really has changed. This is the solution I went with in the end.
Maybe you could reuse code from the NHibernate GenericListType type. At the time I implemented the previous solution I didn't have enough experience to have a go at this.
If you have some prior experience with NHibernate I hope this should help get you started. If not let me know and I will try and put together a more verbose solution.
Features
property as aList
suggesting that it can be manipulated usingAdd
andRemove
etc. Does your list really do that. If not why not expose anIEnumerable
? – Gaffe