Fluent NHibernate conventions – examples

Posted by – November 26, 2009

Fluent NHibernateFluent NHibernate is my favorite extension for NHibernate. I am using it since early betas and I have to say that I love it. One of its underestimated features are conventions. I decided to extract some of them from one of my projects and provide real life examples how they can be used. My conventions are listed below but if you need more information visit Fluent NHibernate Wiki where this feature is described in detail.

ColumnNullabilityConvention – says that if nullability for column has not been specified explicitly, should be set to “NOT NULL”.

public class ColumnNullabilityConvention
    : IPropertyConvention, IPropertyConventionAcceptance
{
    public void Accept(IAcceptanceCriteria<IPropertyInspector> criteria)
    {
        criteria.Expect(x => x.Nullable, Is.Not.Set);
    }

    public void Apply(IPropertyInstance instance)
    {
        instance.Not.Nullable();
    }
}

CreatedAtPropertyAccessConvention – says that every property named CreatedAt should be accessed through camel case field hidden behind it.

public class CreatedAtPropertyAccessConvention
    : IPropertyConvention, IPropertyConventionAcceptance
{
    public void Accept(IAcceptanceCriteria<IPropertyInspector> criteria)
    {
        criteria.Expect(x => x.Property.Name == "CreatedAt");
    }

    public void Apply(IPropertyInstance instance)
    {
        instance.Access.ReadOnlyPropertyThroughCamelCaseField(
            CamelCasePrefix.Underscore);
    }
}

ForeignKeyConstraintNameConvention – says that name of every foreign key constraint representing one to many relation should consist of names of entities for which it was specified.

public class ForeignKeyConstraintNameConvention
    : IHasManyConvention
{
    public void Apply(IOneToManyCollectionInstance instance)
    {
        instance.Key.ForeignKey("{0}_{1}_FK".AsFormat(
        instance.Member.Name, instance.EntityType.Name));
    }
}

ForeignKeyNameConvention – says that name of every column containing foreign key id should consist of name of type which it points to with “Id” suffix.

public class ForeignKeyNameConvention : IHasManyConvention
{
    public void Apply(IOneToManyCollectionInstance instance)
    {
        instance.Key.Column(instance.EntityType.Name + "Id");
    }
}

PrimaryKeyNameConvention - says that name of every column representing primary key should consist of entity name and “Id” suffix.

public class PrimaryKeyNameConvention : IIdConvention
{
    public void Apply(IIdentityInstance instance)
    {
        instance.Column(instance.EntityType.Name + "Id");
    }
}

ReferenceConvention – says that name of column referenced in many to one convention should consist of entity name and “Id” suffix.

public class ReferenceConvention : IReferenceConvention
{
    public void Apply(IManyToOneInstance instance)
    {
        instance.Column(instance.Property.PropertyType.Name + "Id");
    }
}

StringColumnLengthConvention – says that if length for string column has not been specified, it should be set to 100.

public class StringColumnLengthConvention
    : IPropertyConvention, IPropertyConventionAcceptance
{
    public void Accept(IAcceptanceCriteria<IPropertyInspector> criteria)
    {
        criteria.Expect(x => x.Type == typeof(string))
            .Expect(x => x.Length == 0);
    }

    public void Apply(IPropertyInstance instance)
    {
        instance.Length(100);
    }
}

TableNameConvention – says that if name for table has not been specified, it should be created using concatenation of entity name and “s” suffix.

public class TableNameConvention
    : IClassConvention, IClassConventionAcceptance
{
    public void Accept(IAcceptanceCriteria<IClassInspector> criteria)
    {
        criteria.Expect(x => x.TableName, Is.Not.Set);
    }

    public void Apply(IClassInstance instance)
    {
        instance.Table(instance.EntityType.Name + "s");
    }
}

At the end the most important thing which shows that such conventions make sense. With default Fluent NHibernate conventions DDL generated by NHibernate for MySQL looked like this:

alter table `Athlete`  drop foreign key FK9221C9B94070A6F0

drop table if exists Countries

drop table if exists `Athlete`

create table Countries (
     Id INTEGER NOT NULL AUTO_INCREMENT,
     Name VARCHAR(255),
     primary key (Id)
)

create table `Athlete` (
     Id INTEGER NOT NULL AUTO_INCREMENT,
     DisplayName VARCHAR(255),
     Email VARCHAR(255),
     Password VARCHAR(255),
     CreatedAt DATETIME,
     IsActive TINYINT(1),
     Country_id INTEGER,
     primary key (Id)
)

alter table `Athlete`
	add index (Country_id),
	add constraint FK9221C9B94070A6F0
	foreign key (Country_id)
	references Countries (Id)

When I have applied conventions mentioned above to my fluent mappings DDL looks like this:

alter table Athletes  drop foreign key Athletes_Country_FK

drop table if exists Athletes

drop table if exists Countries

create table Athletes (
     AthleteId INTEGER NOT NULL AUTO_INCREMENT,
     DisplayName VARCHAR(100) not null,
     Email VARCHAR(100) not null,
     Password VARCHAR(100) not null,
     CreatedAt DATETIME not null,
     IsActive TINYINT(1) not null,
     CountryId INTEGER,
     primary key (AthleteId)
)

create table Countries (
     CountryId INTEGER NOT NULL AUTO_INCREMENT,
     Name VARCHAR(100) not null,
     primary key (CountryId)
)

alter table Athletes
	add index (CountryId),
	add constraint Athletes_Country_FK
	foreign key (CountryId)
	references Countries (CountryId)

For me it looks much better. Additionally I have made it once and that is it. Now I have to care only about domain model and business logic without thinking about not so important stuff lake names of database objects.

Hey, keep in touch!! Follow me on Twitter, @marcinobel or subscribe to this blog.
14 Comments on Fluent NHibernate conventions – examples

Respond | Trackback

  1. RT says:

    Thank you for a wonderful post. This has helped my code a lot.

    I’m trying to map the Inverse attribute using the IHasManyConvention and I can’t seem to get it right.

    The simplistic instance.Inverse doesn’t even compile.

    The second one I’m struggling with is changing the default nvarchar type to varchar. I got it working using the instance.CustomSqlType(“varchar 100″), but that requires the length to be specified. I wonder whether the type can be specified all by iteslf using some other instance property.

    Again, great post. Thanks.

  2. Fluent NHibernate conventions – examples…

    Thank you for submitting this cool story – Trackback from Fairfeeds.com…

  3. NHibernate 3 and Autofac, can go together? (part 1)…

    In this post, I intend to explain about NHibernate and integrated it with Autofac . And some content…

  4. Thien says:

    Thank you for your great post. But I have the problem with ForeignKeyNameConvention and ReferenceConvention.
    My models
    public class ProductAttribute : Entity
    {
    public ProductAttribute()
    {
    AttributeValues = new List();
    }

    public virtual string Name { get; set; }
    public virtual ProductAttributeDataType DataType { get; set; }
    public virtual IList AttributeValues { get; protected set; }
    public virtual ProductAttributeTemplate AttributeTemplate { get; set; }
    }

    public class ProductAttributeTemplate : Entity
    {
    public ProductAttributeTemplate()
    {

    }

    public virtual string Name { get; set; }
    public virtual IList Attributes { get; protected set; }
    }

    It generate to foreign key: “AttributeTemplateId” and “ProductAttributeTemplateId”

    Could you please help me. Thank you very much

  5. Marcin Obel says:

    Hi Thien,

    Thanks for reading my posts :)
    To be honest, I am not sure what exactly you would like to achieve with this conventions. What foreign key names do you want to have?

    Best regards,
    Marcin

  6. Thien says:

    Sorry for my mistake, —It generate two foreign keys: “AttributeTemplateId” and “ProductAttributeTemplateId”—- And I want only one “AttributeTemplateId”.

    Again, thank you

  7. Polemus says:

    thanx m8, this helped me understand conventions a little bit better.

  8. stuartd says:

    Thanks for these. BTW, in ForeignKeyConstraintNameConvention you have left in your AsFormat extension method without explanation..

  9. Banzai says:

    very good spot, but I have a question, how to do to use a convention scheduled, as you would call you one of those conventions that you created?
    thanks a lot

  10. Banzai says:

    I would like to add another question, how I could do to incorporate constrains the primary keys?
    thanks

  11. Jeff says:

    I’m just getting started with conventions and was wondering if these are still valid I know the post is a bit old and the fluent api has changed a bit.

    thanks for posting these

  12. Braian87b says:

    You can replace:
    instance.Key.ForeignKey(“{0}_{1}_FK”.AsFormat(
    instance.Member.Name, instance.EntityType.Name));

    By:

    instance.Key.ForeignKey(string.Format(“FK_{0}_{1}”, instance.Member.Name, instance.EntityType.Name));

    And it should work just fine!

  13. Jan says:

    Is it possible to change the names of PK an UQ constraints like you’ve done with FK constraint name in ForeignKeyConstraintNameConvention?

  14. athina says:

    Hi,
    I have a problem with foreign key index creation. I see that you have
    alter table Athletes
    add index (CountryId),
    add constraint Athletes_Country_FK
    foreign key (CountryId)
    references Countries (CountryId)

    but I only have

    alter table Athletes
    add constraint Athletes_Country_FK
    foreign key (CountryId)
    references Countries (CountryId).

    Do you have some extra conventions or something to get this index creation?
    Tnx for response

Respond

Comments

Comments