Sammi Sinno

Development - Off The Beaten Path

A development blog that explores everything and puts an emphasis on lesser known community driven projects.


Mappings Across Projects Using NHibernate

Friday, June 2, 2017

When it comes to NHibernate no matter what you do, generally there are many different approaches you can take. If you are thinking about writing a query you can use QueryOver, Linq, Criteria or Hql. What I'll be discussing in this post is how I prefer to set up mappings, which is using the mapping by convention method. While it might not be the most optimal way of doing things when working with legacy databases, setting up conventions to reuse across domain models helps to save a lot of time as well as make things easier to maintain.

A full explaination of the mapping by convention method is beyond this blog post, but you can get a good reference to it by checking out this article.

What I wanted to cover is an implementation that is very simple, but could save your team a lot of headaches down the line if your data layer continues to grow. If you take a look at how I've set up my projects, I was able to separate them based on the type of content I wanted to store:

FastTrack Module Separation

The approach I'm about to show has allowed me to include these projects as needed into separate solutions. I just add the project in and during site startup I'm able to use dependency injection to discover different pieces of each module to correctly wire up the mappings.

Here is where it all begins:

using NHibernate.Mapping.ByCode;

namespace FastTrack.Domain.Interfaces
    public interface IPersistenceConfiguration
        void Configure(ConventionModelMapper mapper);

I've set up this interface to have one method on it, this method takes in the ConventionModelMapper and from there adds any configuration needed for this project.

Here is an example from the FastTrack.GeoManager project:

using FastTrack.Domain.Interfaces;
using FastTrack.GeoManager.DataModels;
using NHibernate.Mapping.ByCode;

namespace FastTrack.GeoManager.Infrastructure
    public class PersistenceConfiguration : IPersistenceConfiguration
        public void Configure(ConventionModelMapper mapper)
            mapper.Class<City>(map =>
                map.ManyToOne(x => x.State, m =>

            mapper.Class<State>(map =>
                map.ManyToOne(x => x.Country, m =>

There wasn't a lot of mappings I had to update since I'm using mapping by convention, I only have to map what I couldn't initially set up "by convention."

Next is how I was able to set this up using Autofac. Here is where all of the implementations are registered:


I had this set up in an Autofac Module. From there I was able to inject all of the implemenations into the class that I use to register my database:

 public class RegisterDatabase : IRunAtInit
        private readonly IEnumerable<IPersistenceConfiguration> _persistenceConfigurations;

        public RegisterDatabase(IEnumerable<IPersistenceConfiguration> persistenceConfigurations)
            _persistenceConfigurations = persistenceConfigurations;

        public void Execute()
            var configuration = new NHibernate.Cfg.Configuration();

            var mapper = new ConventionModelMapper();

            foreach (var persistenceConfiguration in _persistenceConfigurations)

            var hbmMapping = mapper.CompileMappingFor(allEntities);
                .SetProperty(NHibernate.Cfg.Environment.ConnectionString, _configuration.GetConnectionString("FastTrack"))
                .SetProperty(NHibernate.Cfg.Environment.Dialect, "NHibernate.Dialect.MsSql2012Dialect")
                .SetProperty(NHibernate.Cfg.Environment.ConnectionDriver, "NHibernate.Driver.Sql2008ClientDriver, NHibernate")
                .SetProperty(NHibernate.Cfg.Environment.Isolation, "ReadUncommitted")
                .SetProperty(NHibernate.Cfg.Environment.FormatSql, Boolean.FalseString)
                .SetProperty(NHibernate.Cfg.Environment.GenerateStatistics, Boolean.FalseString)
                .SetProperty(NHibernate.Cfg.Environment.Hbm2ddlKeyWords, Hbm2DDLKeyWords.None.ToString())
                .SetProperty(NHibernate.Cfg.Environment.PrepareSql, Boolean.TrueString)
                .SetProperty(NHibernate.Cfg.Environment.PropertyUseReflectionOptimizer, Boolean.TrueString)
                .SetProperty(NHibernate.Cfg.Environment.QueryStartupChecking, Boolean.FalseString)
                .SetProperty(NHibernate.Cfg.Environment.ShowSql, Boolean.FalseString)
                .SetProperty(NHibernate.Cfg.Environment.StatementFetchSize, "100")
                .SetProperty(NHibernate.Cfg.Environment.UseProxyValidator, Boolean.FalseString)
                .SetProperty(NHibernate.Cfg.Environment.UseSecondLevelCache, Boolean.TrueString)
                .SetProperty(NHibernate.Cfg.Environment.UseSqlComments, Boolean.FalseString)
                .SetProperty(NHibernate.Cfg.Environment.UseQueryCache, Boolean.TrueString)
                .SetProperty(NHibernate.Cfg.Environment.WrapResultSets, Boolean.TrueString)
                .SetProperty(NHibernate.Cfg.Environment.CacheProvider, "NHibernate.Caches.SysCache.SysCacheProvider, NHibernate.Caches.SysCache")

Pretty straightforward stuff, but hopefully this can be a launching off point for any other developer thinking of making their data layer more modular.