Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sharing a NHibernate session between UnitOfWork and Repository

I'm trying to implement UnitOfWork and Repository pattern with NHibernate. I'm looking for the best way to share session between unit of work instance and repository instance.

The most obvious way is to introduce ThreadStatic properties in UnitOfWork class

public class UnitOfWork : IUnitOfWork
{
    public static UnitOfWork Current
    {
        get { return _current; }
        set { _current = value; }
    }
    [ThreadStatic]
    private static UnitOfWork _current;

    public ISession Session { get; private set; }

    //other code
}

And then in Repository class:

public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
    protected ISession Session { get { return UnitOfWork.Current.Session; } }

    //other code
}

However I didn't like implementation listed above and decided to find another way to do the same.

So I came with the second way:

public interface ICurrentSessionProvider : IDisposable
{
    ISession CurrentSession { get; }
    ISession OpenSession();
    void ReleaseSession();
}

public class CurrentSessionProvider : ICurrentSessionProvider
{
    private readonly ISessionFactory _sessionFactory;

    public CurrentSessionProvider(ISessionFactory sessionFactory)
    {
        _sessionFactory = sessionFactory;
    }

    public ISession OpenSession()
    {
        var session = _sessionFactory.OpenSession();
        CurrentSessionContext.Bind(session);
        return session;
    }

    public void Dispose()
    {
        CurrentSessionContext.Unbind(_sessionFactory);
    }

    public ISession CurrentSession
    {
        get
        {
            if (!CurrentSessionContext.HasBind(_sessionFactory))
            {
                OnContextualSessionIsNotFound();
            }
            var contextualSession = _sessionFactory.GetCurrentSession();
            if (contextualSession == null)
            {
                OnContextualSessionIsNotFound();
            }
            return contextualSession;
        }
    }

    private static void OnContextualSessionIsNotFound()
    {
        throw new InvalidOperationException("Session is not opened!");
    }
}

where ISessionFactory is singleton resolved by autofac and CurrentSessionContext is CallSessionContext. Then I inject ICurrentSessionProvider in constructors of UnitOfWork and Repository classes and use CurrentSession property to share sessions.

Both approaches seem to be working fine. So I'm wondering are there any other ways to implement this? What is the best practice in sharing session between unit of work and repository?

like image 902
Coffka Avatar asked Mar 24 '15 18:03

Coffka


1 Answers

The best way for you to do this would be to take advantage of the facillities NHibernate already provides to this effect. Please look at section "2.3. Contextual Sessions" on the following documentation: http://nhibernate.info/doc/nh/en/#architecture-current-session

Basically, you need:

  1. A suitable implementation of the ICurrentSessionContext interface that satisfies your needs.
  2. Inform the SessionFactory that you want to use that implementation.
  3. Inject ISessionFactory (your session factory) to any place in which you need to access the "current session".
  4. Obtain the current session by using sessionFactory.GetCurrentSession().

This has the advantage that your session handling strategy will be compatible with how it should be done by most NHibernate projects and it doesn't depend on having anything besides an ISessionFactory in the places you want to access the current session.

Forgot to mention: You may of course implement your own ICurrentSessionContext based on the code you already have listed in your question.

like image 157
Fredy Treboux Avatar answered Nov 05 '22 18:11

Fredy Treboux