Injecting dependencies in NHibernate

Roland, 01.04.2016

Injecting dependencies into entities created by NHibernate looks pretty easy. You need to implement interface IInterceptor. NHibernate does it already providing class EmptyInterceptor. So your class inherits form that.

Below there's a simple implementation that looks at the container every time a poco instance is being created by NHibernate when dehydrating data from database.

    class ContainerResolvingEntityInterceptor : EmptyInterceptor
    {
        private ISession _session;
        private IWindsorContainer container;

        public TestEntityInterceptor(IWindsorContainer container)
        {
            this.container = container;
        }

        public override void SetSession(ISession session)
        {
            _session = session;
        }

        public override object Instantiate(string clazz, EntityMode entityMode, object id)
        {
            object instance = null;
            if (entityMode == EntityMode.Poco)
            {
                var type = Type.GetType(clazz);
                if (type != null)
                {
                    instance = container.Resolve(type);
                    var md = _session.SessionFactory.GetClassMetadata(clazz);
                    md.SetIdentifier(instance, id, entityMode);
                }
            }
            else
            {
                instance = base.Instantiate(clazz, entityMode, id);
            }
            return instance;
        }
    }

Now, when configuring a containere, the entities have to go there too. They can have parameterized constructors accepting services required by the class.

Suppose a class Employee depending on an interface ISalaryCalculator used to compute salary:

public class Employee : IEmployee
{
    private readonly ISalaryCalculator salaryCalculator;

    protected Employee() { }

    public Employee(ISalaryCalculator salaryCalculator)
    {
        this.salaryCalculator = salaryCalculator;
    }

    public virtual int Id { get; set; }

    public virtual string FirstName { get; set; }

    public virtual string LastName { get; set; }

    public virtual DateTime BirthDate { get; set; }

    public virtual DateTime EmployedFrom { get; set; }

    public virtual DateTime? EmployedUntil { get; set; }

    public virtual string Address { get; set; }

    decimal IProvidingSalary.CalculateSalary()
    {
        return salaryCalculator.CalculateSalary(this);
    }
}

The container contains registration of the entity as well as the required dependency:

public void InitializeContainer()
{
    container = new WindsorContainer();
    container.Register(
        Component.For<ISalaryCalculator>().ImplementedBy<SalaryCalculator>(),
        Component.For<Employee>().ImplementedBy<Employee>().LifeStyle.Transient,
        Component.For<ISessionFactory>().UsingFactoryMethod((k, ctx) => CreateSessionFactory()));
}

Looks nice. And works very well.