July 30 2015

Fluent NHibernate - Unproxy Entity Objects with AutoMapper

I ran into a bug a few days ago with a CMS I'm developing for a law firm marketing website in Sydney, the CMS is built with ASP.NET MVC 5 and Fluent NHibernate as the ORM, I'm using the Unit of Work and Repository pattern to create a session per request that begins a transaction at the start of each request and commits the transaction at the end of the request.

The bug I found was caused by the object being returned from my repository being an NHibernate proxy object rather than a direct instance of my entity class, so any changes made to this proxy object were getting automatically saved at the end of each request when the UoW transaction was committed, whereas I only wanted changes to be saved when I explicitly call my repository save methods.

In order to get a plain old C#/CLR object (POCO) I needed to unproxy the NHibernate object, which can be done with Automapper's DynamicMap method like this:

Unproxy NHibernate Object

public T GetById(int id)
{
    // unproxy nhibernate object with automapper
    return Mapper.DynamicMap<T>(Session.Get<T>(id));
}

Another method I found suggested online is to use the built in NHibernate method (T)Session.GetSessionImplementation().PersistenceContext.Unproxy(Session.Get<T>(id)); but this didn't work for me, maybe because I'm using generic type parameters but I'm not sure, in any case I think the Automapper method is cleaner.

One thing to remember is update an object that has been unproxied you need to call Session.Merge() to hook it back into the NHibernate session (or re-proxy) like this:

Merge (Reproxy) NHibernate Object

public void Update(T entity)
{
    // re-attach entity to session and update
    Session.Merge<IEntity>(entity);
}

Below is the complete generic repository class including the above methods, for more details on the Unit of Work and Repository pattern and to access a demo project check out this post.

Generic Repository that Unproxies and Merges Entities

public class Repository<T> : IRepository<T> where T : IEntity
{
    private UnitOfWork _unitOfWork;
    public Repository(IUnitOfWork unitOfWork){
        _unitOfWork = (UnitOfWork)unitOfWork;
    }

    protected ISession Session { get { return _unitOfWork.Session; } }

    public IQueryable<T> GetAll()
    {
        return Session.Query<T>();
    }

    public T GetById(int id)
    {
        // unproxy nhibernate object with automapper
        return Mapper.DynamicMap<T>(Session.Get<T>(id));
    }

    public void Create(T entity)
    {
        Session.Save(entity);
    }

    public void Update(T entity)
    {
        // re-attach entity to session and update
        Session.Merge<IEntity>(entity);
    }

    public void Delete(int id)
    {
        Session.Delete(Session.Load<T>(id));
    }
}

 

C# and Web Development Sydney

Feel free to drop me a line if you're looking for web development services in Sydney Australia, I also provide remote contracting services for clients outside Sydney.


Sponsored by