Implementing Fluent-nHibernate

To follow on from my short and brief post nHibernate mapping files no more, I have implemented fluent-nhibernate very successfully and easily in my own application. In this example I am going to implement the ApplicationUser, Title and Role domain entities. All my entities derived from a abstract class called EntityBase. This base class is very little, it holds an Id (int) property and an abstract method “IsValid()”.

public abstract class EntityBase
{
    private int id;

    protected EntityBase() : this(0) { }

    protected EntityBase(int id)
    {
        this.id = id;
    }

    public int Id
    {
        get { return this.id; }
    }

    public abstract bool IsValid();
}

I will start with the simplest class first being the Title class.

public class Title : EntityBase
{
    public string Name { get; set; }

    public override bool IsValid()
    {
        return !string.IsNullOrEmpty(Name);
    }
}

Before I do the mapping for the title class, I need to put the mappings in the right place. I have a Repository layer that contains all my repositories for all of my root entities. All of my repositories inherit from “EntityRepository” which is has a dependency on an implementation of IPersistenceRepository. This is my own interface that does not expose any leaky abstractions from a technology like nHibernate.

So getting to the point, I have an assembly called “RussellEast.Repositories” and a “RussellEast.Repositories.NHibernate” assembly which references the “RussellEast.Repositories” assembly as it holds the IPersistenceRepository interface. The “RussellEast.Repositories.NHibernate” has a class called “NHibernateRepository” which implements the IPersistenceRepository interface. The RussellEast.Repositories.NHibernate is the only assembly in my solution to know about nhibernate so I am going to place all my maps in this assembly under a folder called “Maps” and reference the Fluent-nHibernate assembly.

To implement Fluent-nhibernate there is not a need to use the repository pattern, I am a big fan of DDD so I do. I just wanted to explain where I was going to place my mappings as I don’t want them in my core application or in my domain model.  For my information on how I have created my repositories, please read my previous post Implementing the Repository and Finder patterns.

Enough with the ramblings, here is the mapping for the Title entity

using FluentNHibernate;
using FluentNHibernate.Mapping;
using RussellEast.Domain.People;

namespace RussellEast.Repositories.NHibernate.Maps.People
{
    public class TitleMap : ClassMap<Title>
    {
        public TitleMap()
        {
            Id(x => x.Id).Access
                .AsReadOnlyPropertyThroughLowerCaseField()
                .GeneratedBy.Identity();

            Map(x => x.Name).CanNotBeNull().WithLengthOf(20);
        }
    }
}

If you can see from the TitleMap, I am mapping the Id to my Id readonly property in my EntityBase class that the Title entity derives from. The Fluent interface allows me to set up the access for nhibernate to populate it and generation for my Id. The Map method wires up the Name property and sets the field size and not null constaint. (sorry for stating the obvious).

Now for the Role Entity.

public class Role : EntityBase
{
    public string Name { get; set; }
    public bool IsSystemRole { get; set; } 

    public override bool IsValid()     
    { 
        return !string.IsNullOrEmpty(Name);
    }
}

Not much different from the Title Entity, just the additional “IsSystemRole” property. Here is the mapping class.

public class RoleMap : ClassMap<Role>
{
    public RoleMap()
    {
        Id(x =>x.Id).Access
            .AsReadOnlyPropertyThroughLowerCaseField()
            .GeneratedBy.Identity();
        Map(x =>x.Name).CanNotBeNull().WithLengthOf(50);
        Map(x => x.IsSystemRole);
    }
}

This is similar to the TitleMap, so not much to learn here. So now to the ApplicationUser entity. An ApplicationUser is a person, i have other domain entities in my application that are people, so i have an Person entity.

using System.Text.RegularExpressions;

namespace EWS.Portcullis.Domain.People
{
    public abstract class Person : EntityBase
    {
        private string email;

        public Title Title { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }

        public string Email
        {
            get { return email; }
            set 
            {
                if (IsEmailValid(value))
                {
                    email = value;
                }
            }
        }

        protected bool IsEmailValid(string value)
        {
            const string pattern = @"^[A-Za-z0-9._%-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$";

            bool isValid = true;

            if (!string.IsNullOrEmpty(value))
            {
                Regex regex = new Regex(pattern);

                isValid = regex.IsMatch(value);
            }

            return isValid;
        }
    }
}

My ApplicationUser entity derives from Person

    public class ApplicationUser : Person
    {
        public string LoginName {get; set;}
        public int Salt { get; set; }
        public string Password { get; set; }
        public DateTime LastLoggedIn { get; set; }
        public Guid Token { get; set; }
        public IEnumerable Roles { get; set; }

        public override bool IsValid()
        {
            return (!(string.IsNullOrEmpty(FirstName) 
                || string.IsNullOrEmpty(LastName)));
        }
    }

My ApplicationUserMap looks like this.

    public class ApplicationUserMap : ClassMap
    {
        public ApplicationUserMap()
        {
            Id(x => x.Id).Access
                .AsReadOnlyPropertyThroughLowerCaseField()
                .GeneratedBy.Identity();
            Map(x => x.FirstName).CanNotBeNull().WithLengthOf(100);
            Map(x => x.LastName).CanNotBeNull().WithLengthOf(100);
            Map(x => x.Email).WithLengthOf(100);
            Map(x => x.LoginName).WithLengthOf(50);
            Map(x => x.Password).WithLengthOf(255); 
            Map(x => x.Salt);
            Map(x => x.LastLoggedIn);
            Map(x => x.Token);
            References(x => x.Title);
            HasManyToMany(x => x.Roles).AsBag();
        }
    }

As you will see, I use the References method to map the Title association. As for Roles, I have an ApplicationUser that can belong to many Roles and a Role can have many ApplicationUsers. I define this association using the HasManyToMany method and set as “AsBag”. This works great as my Role property in the ApplicationUser is type of IEnumerable. This is nice side effect here is that I don’t have to have a specialised collection type like “ISet” in my domain layer.

The final bit of code needed is to configure NHibernate which is shown in the code snippet below.

private static readonly ISessionFactory sessionFactory;
private ISession currentSession;

static NHibernateSessionLocator()
{
    sessionFactory = GetConfiguration().BuildSessionFactory();
}

private static Configuration GetConfiguration()
{
     Configuration cfg = new Configuration().Configure();

     string mappingAssembly = ConfigurationManager
          .AppSettings["NHibernate.Mapping.Assembly"];

      var persistenceModel = new PersistenceModel();

      persistenceModel
           .addMappingsFromAssembly(Assembly.Load(mappingAssembly));
      persistenceModel.Configure(cfg);

      return cfg;
}
        
public ISession ActiveSession()
{
     if (currentSession == null)
     {
         currentSession = sessionFactory.OpenSession();
     }

      return currentSession;
}

public void CloseActiveSession()
{
	...
}

public void UpdateDatabaseSchema()
{
     Configuration cfg = GetConfiguration();

     SchemaUpdate schemaUpdate = new SchemaUpdate(cfg);

     schemaUpdate.Execute(true, false);
}

The UpdateDatabaseSchema method is not part of my application but when i add a new entity and Map to my application i run this method from debug mode as it outputs the SQL DDL commands to the output window, which i use to create my tables. Here is a snippet of my application config file:

<appSettings>
    <add key="NHibernate.Mapping.Assembly" 
        value="RussellEast.Repositories.NHibernate"/>
</appSettings>

Using fluent-nhibernate has made my life so much easier.  I applaud the developers that created this.

Advertisements

5 responses to “Implementing Fluent-nHibernate

  1. I’m using Fluent NH for mapping and NH as ORM in my C# application.. The problem is
    with schemaupdate class.. if I create an instance of that.. using the configuration I
    got from my exposeconfiguration function.. It doesnot update the schema.. I need some
    better documentation on SchemaUpdate class.. or might be.. setting the configuration
    to accomodate the new schema in an old database.. for versioning purposes..

    I have tried a lot of variations but no DDL command is reflected on the actual
    database using SchemaUpdate 😦

    • Sushant, you are not alone. I have also have problems using the update schema function. What I do is ask the tool to ouput the sql to the ouput window and then pick the bits from the output that i want. This is a pretty crap way of doing it. I have though looked at other ways to manage database scripts. In my hunt so far, my favourite is DBDeploy.NET.

  2. Hi, I know maybe you posted about the “way” you does these things, but because I’m implementing a solution on these concepts, it will be useful to have the ISessionLocator|NHibernateSessionLocator because I’m courios about your implementation.. It’s possible to have the code? How?
    Thanks in advance

  3. Pingback: Fluent NHibernate « Net

  4. Hi , Let me assume , if I want to store “IsActive” in relation many to many Application User and roles ,How can I map “IsActive” and in which class ?
    Table ApplicationUser_Roles will have these fields:

    ApplicationUserId;
    RoleId;
    IsActive;
    Thanks in advance

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s