Defining Acceptance criteria for mapping conventions in NHibernate

Today I'm hosting a post from Leeran Yarhi, one of the developers in my team:

Hi guys,

I’m Leeran Yarhi, a developer in Yossi’s team.

Recently we had a problem while mapping one of our domain entities with Fluent NHibernate. We upgraded our app to use NHibernate 3 in conjunction with Fluent NHibernate 1.2. When we did that, some of our tests failed.

For example, let’s have a look at this entity:

public class User  
{
    public virtual int Id { get; set; }
    public virtual string FirstName { get; set; }
    public virtual string LastName { get; set; }
    public virtual string FullName { get; private set; }
}

And it’s mapping:

public class UserMap : ClassMap<User>  
{
    public UserMap()
    {
        Id(x => x.Id);
        Map(x => x.FirstName);
        Map(x => x.LastName);
        Map(x => x.FullName).Formula("first_name || ' ' || last_name");
    }
}

As you can see, User has a property named FullName, which is actually a concatenation of FirstName and LastName. Of course I don’t really want to map this property to our Database. This is why I’m defining it a Formula, so that my Users table won’t really have a column for FullName.

All good, but the problem starts when I try to use this PropertyConvention :

public class PropertyUnderscoreConvention : IPropertyConvention  
{
    public void Apply(IPropertyInstance instance)
    {
        instance.Column(Inflector.Underscore(instance.Property.Name));
    }
}

NHibernate will throw an exception because it’s trying to give a name to a column that doesn’t exist. The solution for this problem is to somehow define to my convention when it should apply, or in other words – Acceptance Criteria.

Fluent NHibernate gives us an API for defining the criteria that a mapping must satisfy for a convention to be applied to it. Exactly what I need.

The Convention class will now implement another interface: IAcceptanceCriteria<TInspector>, which contains the method Accept. This method defines the above criteria.

Let’s see some code, this is how my new convention looks like:

public interface IPropertyConventionAcceptance : IConventionAcceptance<IPropertyInspector>  
{
}

public class PropertyConvention : IPropertyConvention, IPropertyConventionAcceptance  
{
    public void Apply(IPropertyInstance instance)
    {
        instance.Column(Inflector.Underscore(instance.Property.Name));
    }

    public void Accept(IAcceptanceCriteria<IPropertyInspector> criteria)
    {
        criteria.Expect(x => x.Formula == null);
    }
}

Now, my criteria will be applied only on properties that doesn’t have Formula, and all the mapping will work fine.

Yossi Shmueli

Technologist, enjoy solving technical challenges for real world applications. Keeping it Green since 1995

comments powered by Disqus