One of the things you usually end up wanting to configure on a case-to-case basis when using NHibernate is cascading – i.e. which relations should NHibernate take responsiblity for saving.

An example could be in DDD terms where you have an aggregate root, that contains some stuff. Let’s take an example with a Band which is the subject of the BandMember role, which in turn references another aggregate root, User, that is the object of the band member role.

It is OK for us that we need to save a User and a Band in a repository, that’s the idea when dealing with aggregate roots. But everything beneath an aggregate root should be automatically persisted, and the root should be capable of creating/deleting stuff beneath itself without any references to repositories and stuff like that.

So how do we do that with NHibernate? Well, it just so happens that NHibernate can be configured to cascade calls to save, delete, etc. through relations, thus allowing the aggregate root to logically “contain” its entities.

This is all fine and dandy, but when Fluent NHibernate is doing its automapping, we need to be able to give some hints when we want cascading to happen. I usually want to be pretty persistence ignorant, BUT sometimes I just want to be able to do stuff quickly and just get stuff done, so I usually end up “polluting” my domain model with a few attributes that give hints to a convention I use.

Consider this:

public class Band : EntityBase
{
	public Band()
	{
		BandMembers = new List<BandMember>();
	}
 
	public virtual string Name { get; set; }
 
	[Cascade]
	public virtual IList<BandMember> BandMembers { get; set; }
 
	public virtual void AddBandMember(User user, BandMemberType bandMemberType)
	{
		var bandMember = FindExistingBandMember(user) ?? new BandMember(user);
		bandMember.BandMemberType = bandMemberType;
	}
 
	public virtual void RemoveBandMember(User user)
	{
		BandMembers.Remove(FindExistingBandMember(user));
	}
 
	BandMember FindExistingBandMember(User user) 
	{
		return BandMembers.ToList().Find(b => b.User == user);
	}
}
 
public enum BandMemberType 
{
	Member, Administrator
}
 
public class BandMember : EntityBase
{
	public BandMember(User user)
	{
		User = user;
	}
 
	public virtual BandMemberType BandMemberType { get; set; }
 
	public virtual User User { get; set; }
}
 
public class User : EntityBase
{
	public virtual string Name { get; set; }
}

Notice that little [Cascade]-thingie in there? It’s implemented like this:

public class CascadeAttribute : Attribute
{
}

Trivial – but I want that to be spotted by Fluent NHibernate to make the BandMembers collection into a cascade="all-delete-orphan", which in turn will cause the methods AddBandMember and RemoveBandMember to be able to update the DB.

I do this with a CascadeConvention, which is my implementation of the IHasManyConvention and IReferenceConvention interfaces. It looks like this:

public class CascadeConvention : IHasManyConvention, IReferenceConvention
{
	public void Apply(IManyToOneInstance instance)
	{
		var property = instance.Property;
 
		if (!HasAttribute(property)) return;
 
		Console.WriteLine("CascadeAll on {0}.{1}", property.DeclaringType.Name, property.Name);
 
		instance.Cascade.All();
	}
 
	public void Apply(IOneToManyCollectionInstance instance)
	{
		var property = instance.Member;
 
		if (!HasAttribute(property)) return;
 
		Console.WriteLine("CascadeAllDeleteOrphan on {0}.{1}", property.DeclaringType.Name, property.Name);
 
		instance.Cascade.AllDeleteOrphan();
	}
 
	bool HasAttribute(ICustomAttributeProvider provider)
	{
		return provider.GetCustomAttributes(typeof(CascadeAttribute), false).Length == 1
	}
}

What is left now is to make sure Fluent NHibernate picks up my convention and uses it. I usually do this by throwing them into the same assembly as my entities and do something like this when configuring FNH:

new AutoPersistenceModel()
        // (...)
        .Conventions.Setup(s => s.AddFromAssemblyOf<EntityBase>())
        .Configure(configuration);

- which will cause all conventions residing in the same assembly as EntityBase to be used.

This works really good for me, because it makes it really easy and quick to configure cascading where it’s needed – I don’t have to look deep into an .hbm.xml file somewhere or try to figure out how cascading might be configured somewhere else – the configuration is right where it’s relevant and needed.

Extremist PI-kinds-of-guys might not want to pollute their domain models with attributes, so they might want to use another way of specifying where cascading should be applied. Another approach I have tinkered with, is to let all my entities be subclasses of an appropariate base class – like e.g. AggregateRoot (implies no cascading), Aggregate (implies cascading), and Component (implies that the class is embedded in the entity).

The great thing about Fluent NHibernate is that it’s entirely up to you to decide what kind of intrusion offends you the least :)

Why

I have loved NHibernate right from when I first learned how to use it, and I have loved NHibernate beneath Castle ActiveRecord since I found out that ActiveRecord could reduce the pain I felt because of NHibernate’s .hbm.xmhell.

However, using Castle ActiveRecord requires you to “pollute” your otherwise beautiful and pure domain model with database mapping metadata in the form of .NET attributes. If you are a PI kind of kind, this might be too much to ask. But if you (like me) are willing to relax your ideals a bit to gain the extra productivity, you might be happy to do so – even though it hurts your feelings a little bit every time you have to punch in that [Property(Access == PropertyAccess.FieldCamelCase)]-attribute for the 100th time…

But there is another option: Fluent NHibernate – an option that embraces the philosophy of “convention over configuration”, which seems to be getting a lot of attention these days in the .NET world.

EDIT: Oh yeah, and now it’s here.

How

If you know NHibernate, you know that you use it like this:

  1. Create a Configuration.
  2. Use the configuration to build an ISessionFactory which you store somewhere.
  3. And then use that session factory repeatedly to open ISessions which in turn are used to do stuff with the DB.

So, what can Fluent NHibernate do for you? Well, FNH is actually pretty simple – it helps with the Configuration part of NHibernate. As soon as the Configuration is finished, Fluent NHibernate is out, and from then on it’s pure NHibernate again.

First, I will show a short example – and then I will explain how much is actually accomplished by issuing these ridiculously simple statements. Behold:

      var configuration = Fluently.Configure()
        .Database(MsSqlConfiguration
                            .MsSql2005
                            .ConnectionString("server=.;initial catalog=db;integrated security=sspi;"))
        .BuildConfiguration();
 
      new AutoPersistenceModel()
        .AddEntityAssembly(typeof (Base).Assembly)
        .Where(type => type.Namespace != null && type.Namespace.Contains("Entities"))
        .Setup(s => { s.IsBaseType = t => t == typeof (Base); })
        .Conventions
        .Setup(s => s.AddFromAssemblyOf<Base>())
        .Configure(configuration);
 
      var sessionFactory = configuration.BuildSessionFactory();

If you look at the statements above, I can tell you that it configures FNH to assume the following:

  • All of my entities can be found in the assembly containing Base inside any namespace containing the string “Entities”.
  • All of my entities derive from Base, which is just a very simple entity layer supertype containing nothing more than an Id property of type Guid.
  • Any conventions found in the same assembly as Base will be used by FNH to alter the mappings.

Is that it? Well almost… The code above will make FNH map everything as good as it can, but I still want to alter the mapping in certain places – and that is done through the conventions found in my entity asseembly. At the moment I have 2 conventions:

  1. CascadeAttributeConvention, which is an IHasManyConvention and an IReferenceConvention that looks over any one-to-many and many-to-one relations in my domain, setting cascade to all or all-delete-orphan if it finds a CascadeAttribute on the property.

    This allows me to do stuff like

    [Cascade]
    public virtual IList<BandMember> BandMembers { get; set; }

    and expect the collection of band members to live and die and be updated with its aggregate, Band.

  2. PluralizeTableNamesConvention, which is an implementation of IClassConvention I use to pluralize table names. It contains code like this:
    public void Apply(IClassInstance instance)
    {
      instance.Table(Pluralize(instance.EntityType.Name));
    }

    where the Pluralize method does whichever magic is required to pluralize names from my domain (usually by appending an “s”: Band => Bands, BandMember => BandMembers etc.).

And that is it!

I expect a few more conventions to come along as development progresses – e.g. in other projects I have run into the need to be able to specify that one string should be nvarchar(255) and another string nvarchar(8192) in the DB, which I have solved with an IPropertyConvention that looks for the presence of a LengthAttribute containing the desired length.

And that is why I really like Fluent NHibernate – it allows me to leverage the most powerful ORM alive in the easiest possible way, making NHibernate feel lean and lightweight, encouraging me to follow conventions in my codebase. What’s not to like?

EDIT: Please note that this way of configuring Fluent NHibernate is obsolete since the RCs. Look here for an example on how to customize the automapping on Fluent NHibernate 1.0 RTM.

Fluent NHibernate is cool because there is too much XML in the world – so I appreciate any initiative to bring down the amount of XML. Configuring NHibernate using simple code and strongly types lambdas is actually pretty cool.

However, there is also too much code in the world – therefore, the AutoPersistenceModel is my preferred way of configuring Fluent NHibernate. It allows me to focus on what really matters: my domain model.

But don’t you lose control when all your database mapping is done automatically adhering only to a few conventions? No! You can always customize your mappings and complement/override the auto mappings. But then we can easily end up customizing too much, and then we are back to writing too much code.

Therefore, I would like to show how I use attributes to spice up my NHibernate mapping and add that tiny bit of extra customization that I need. I would like to be able to make the following entity:

public class ImportantBusinessEntity
{
    public virtual Guid Id { get; set; }
 
    [Indexed, Unique]
    public virtual string Name { get; set; }
 
    [Length(2048)]
    public virtual string Description { get; set; }
 
    [Encrypted]
    public virtual string CodeName { get; set; }
}

That is, I want to be able to describe some extra mapping related stuff by applying a few non-instrusive attributes in my domain model.

How can that be accomplished with Fluent NHibernate? Easy! Like so:

var model = new AutoPersistenceModel
{
    Conventions =
      {
          // (...) my ordinary mapping conventions in here
      }
}
 
model.Conventions.ForAttribute<IndexedAttribute>(IndexedAttribute.AlterMap);
model.Conventions.ForAttribute<UniqueAttribute>(UniqueAttribute.AlterMap);
model.Conventions.ForAttribute<LengthAttribute>(LengthAttribute.AlterMap);
model.Conventions.ForAttribute<EncryptedAttribute>(EncryptedAttribute.AlterMap);

and then I have made the following attributes:

IndexedAttribute.cs:

 
[AttributeUsage(AttributeTargets.Property)]
public class IndexedAttribute : Attribute
{
	public static void AlterMap(IndexedAttribute attr, IProperty prop)
	{
		prop.SetAttribute("index", "IX__" + prop.Property.Name);
	}
}

UniqueAttribute.cs (works with ordinary as well as composite unique constraints):

[AttributeUsage(AttributeTargets.Property)]
public class UniqueAttribute : Attribute
{
	readonly string key;
 
	public UniqueAttribute()
	{
	}
 
	public UniqueAttribute(string key)
	{
		this.key = key;
	}
 
	public static void AlterMap(UniqueAttribute attr, IProperty prop)
	{
		if (attr.key == null)
		{
			prop.SetAttribute("unique", "true");
		}
		else
		{
			prop.SetAttribute("unique-key", attr.key);
		}
	}
}

LengthAttribute.cs:

[AttributeUsage(AttributeTargets.Property)]
public class LengthAttribute : Attribute
{
	readonly int length;
 
	public LengthAttribute(int length)
	{
		this.length = length;
	}
 
	public static void AlterMap(LengthAttribute attr, IProperty prop)
	{
		prop.SetAttribute("length", attr.length.ToString());
	}
}

EncryptedAttribute.cs:

[AttributeUsage(AttributeTargets.Property)]
public class EncryptedAttribute : Attribute
{
	public static void AlterMap(EncryptedAttribute attr, IProperty prop)
	{
		prop.SetAttribute("type", typeof(EncryptedStringUserType).AssemblyQualifiedName);
	}
}

If you are an extremist PI kinda guy you might think this is wrong – and I might agree with you a little, but I am also a pragmatic kinda guy, and I think this is a great compromise between being fairly non-intrusive but still expressive, effective and clear.

© 2010 mookid on code Suffusion WordPress theme by Sayontan Sinha