Having defined a domain model I want to figure out how to do the rest of work.
DATA ACCESS LAYER
I had read before that it is not necessary to code own UnitOfWork implementation over ISession (thogh I found a much information on how to do it pretty well). So I’m quite confused.. I have repository interface like this:
public interface IRepository<T> where T: AbstractEntity<T>, IAggregateRoot
{
T Get(Guid id);
IQueryable<T> Get(Expression<Func<T, Boolean>> predicate);
IQueryable<T> Get();
T Load(Guid id);
void Add(T entity);
void Remove(T entity);
void Remove(Guid id);
void Update(T entity);
void Update(Guid id);
}
Where in the concrete implementation there are two options:
OPTION A
Is to inject ISessionFactory thru constructor and have something similar to:
public class Repository<T> : IRepository<T> where T : AbstractEntity<T>, IAggregateRoot
{
private ISessionFactory sessionFactory;
public Repository(ISessionFactory sessionFactory)
{
this.sessionFactory = sessionFactory;
}
public T Get(Guid id)
{
using(var session = sessionFactory.OpenSession())
{
return session.Get<T>(id);
}
}
}
OPTION B
Is to use NHibernateHelper class
using(var session = NHibernateHelper.GetCurrentSession())
{
return session.Get<T>(id);
}
Where NHibernateHelper is
internal sealed class NHibernateHelper
{
private const string CurrentSessionKey = "nhibernate.current_session";
private static readonly ISessionFactory sessionFactory;
static NHibernateHelper()
{
sessionFactory = new Configuration().Configure().BuildSessionFactory();
}
public static ISession GetCurrentSession()
{
HttpContext context = HttpContext.Current;
ISession currentSession = context.Items[CurrentSessionKey] as ISession;
if(currentSession == null)
{
currentSession = sessionFactory.OpenSession();
context.Items[CurrentSessionKey] = currentSession;
}
return currentSession;
}
public static void CloseSession()
{
HttpContext context = HttpContext.Current;
ISession currentSession = context.Items[CurrentSessionKey] as ISession;
if(currentSession == null)
{
return;
}
currentSession.Close();
context.Items.Remove(CurrentSessionKey);
}
public static void CloseSessionFactory()
{
if(sessionFactory != null)
{
sessionFactory.Close();
}
}
}
What’s option is prefered?
Why(besides the injection)?
If I use option A where do I place configuration of ISessionFactory?
Should it be placed somewhere in ASP.NET MVC project? How?
Thank you for reading the monster-question! Your guidance is appreciated!
How to handle injecting dependencies with mvc is somewhat version specific but it always helps to use a real Dependency Injection (DI) container. However you slice it, this solution will need you to Inject an ISession into the Repository rather than an ISessionFactory. This allows your DI container to manage the lifetime of the session properly.
Assuming you’re using Asp.Net MVC 3 and dont have an attachment to a specific DI container already, fire up your Nuget console and type:
This will go, download Ninject (which is a DI container) and configure your mvc application to use it. It will also create a file ~/App_Start/NinjectMVC3.cs which is where you’ll configure your dependencies as such.
The first statement tells ninject that when something requires an ISessionFactory, it should lazily initialize NHibernate and create one. This session factory is then to be held as an application-wide singleton for the lifetime of the application.
The second statement tells ninject that when something requires an ISession, it should get an instance of ISessionFactory and call OpenSession(). This Session is then reused within the scope of the request and destroyed at the end of the request.
The third statement tells ninject that when something requires an IRepository of any type, it should just new one up using it’s built in logic to resolve dependencies.
From here you can write your code as follows and everything should just work.
With regards to the Repository I’d like to point you to an excelent blog post Repository is the new Singleton