Using Bidirectional Associations in nhibernate can be tricky, the problem is that you need to manage associations for both ends. This is really important: suppose you have a class called Parent with a collection of childs called Childs, and a child class with a property called Parent; if you expose these two property to the user, you can write this
Parent John = new Parent(); Parent Mark = new Parent(); Child Bart = new Child(); John.Childs.Add(Bart); Bart.Parent = Mark;
With such a code Bart’s parent is Mark, but Bart is in John Child collection, this is WRONG. To avoid this problem you should maintain integrity in the domain model, managing the consistency of the relationship. Suppose you have the same situation with two objects, a StockKeepingUnit and a StockContainer, here it is the code for StockKeepingUnit
public virtual StockContainer Parent { get { return parent;} set { if (parent != null) parent._Content.Remove(this); parent = value; if (value != null) value._Content.Add(this); } } private StockContainer parent;
As you can see in the setter part I first check if this object has a parent, if yes we need to remove it from the _Content collection of the parent object (because actually I’m detatching from it); then if the value is different from null it means that we have a new parent, so the object assign itself to the _Content collection of the new father to mantain integrity. Surely you now need to map this property in directly on the field to avoid problem
<many-to-one name="parent" access="field" class="StockKeepingUnit" ... />
It is of fundamental importance that you map to the field, this because when nhibernate rebuild the object from database, you must avoiding calling the Set part of the Parent property, because the coherence of the objects are guaranteed by nhibernate itself. Now here is how I implemented the Collection part on the SockContainer class
public virtual IEnumerable <StockKeepingUnit> Content { get { return _Content;} } internal virtual ISet<StockKeepingUnit> _Content { get { return content ?? (content = new HashedSet <StockKeepingUnit>()); } set { content = value; } } private ISet<StockKeepingUnit> content;
First of all the ISet class is a private field, and the accessor property, called _Content, is internal because it must be accessed by the StockKeepingUnit code seen before, but must not be accessed from external code. The property is implemented with lazy creation, if the content property is null, I simply create an HashedSet, this is useful when you first create the object, because initially this property is null. When nhibernate rebuild the object from database data, the content private field is set by nhibernate, so I can avoid unnecessary creation of HashedSet. With this kind of structure you can map nhibernate to the _Content property and not to the field.
Now a question arise: How can the user of this class access the Collection of StockKeepingUnit if the _Content property is private? The answer is in the property Content that is of type IEnumerable<StockKeepingUnit>. With Ienumerable I permit the user to use fully LINQ syntax to access collection of StockKeepingUnit, this is enough for most scenarios because with LINQ you can iterate, filter, select and doing whatever you want to access all StockKeepingUnit contained in a stockContainer.
Alk
Tags: NHibernate Domain Model

May 25th, 2009 at 7:04 am
Does someone have used this pattern in a real projet. It looks very smart but i can’t see the limits …
July 1st, 2009 at 10:36 am
Mapping to the internal property demands that you keep your mappings in the same assembly as your domain, which is a topic I’ve seen debated.
Nice posting.
Cheers,
Berryl
July 2nd, 2009 at 1:43 am
THis is not true
, nhibernate uses reflection and can map even private members, location of the mappings is not important, and sure, I prefer keeping mappings outside the assembly that contains my entities.
alk.
July 9th, 2009 at 7:18 pm
I was thinking Fluent NHibernate. I’d like to use this mapping pattern too, and keep my mappings in a different assembly from the domain, but it cannot see the internal ISet from there to map it.
July 9th, 2009 at 8:39 pm
Yes, you can keep the mapping in a different assembly and use FNH to get it done. Instead of mapping to the internal property, map to the public one even though it is an IEnumerable. The specify the access to the field, ie
mapping.HasMany(x => x.Staff) // the public property
.AsSet()
// private field, in my case _staff
.Access.AsLowerCaseField(Prefix.Underscore)
.Inverse()
.Cascade.SaveUpdate();
The is still an internal _InternalStaff supporting the bidirectional integrity, but your mapping needn’t care.
Thanks for pointing out this could be done alkampfer