nhibernate : Repository Session Management
At the moment my repository has 2 constructors. When i call these from my mvc website i am alway calling first constructor and thus openin开发者_开发问答g a new session. Should i been passing in the session. How should i be doing this.
public CompanyRepository()
{
_session = NHibernateHelper.OpenSession();
}
public CompanyRepository(ISession session)
{
_session = session;
}
public class NHibernateHelper
{
private static ISessionFactory _sessionFactory;
private static ISessionFactory SessionFactory
{
get
{
if (_sessionFactory == null)
{
var configuration = new Configuration();
configuration.Configure();
configuration.AddAssembly(typeof(UserProfile).Assembly);
configuration.SetProperty(NHibernate.Cfg.Environment.ConnectionStringName,
System.Environment.MachineName);
_sessionFactory = configuration.BuildSessionFactory();
}
return _sessionFactory;
}
}
public static ISession OpenSession()
{
return SessionFactory.OpenSession();
}
}
I'm using the Ninject IOC container ( very new to me ). I have the following container. How would i bind the ISession to the CompanyRepository.
private class EStoreDependencies : NinjectModule
{
public override void Load()
{
Bind<ICompanyRepository>().To<CompanyRepository>();
Bind<IUserProfileRepository>().To<UserProfileRepository>();
Bind<IAddressRepository>().To<AddressRepository>();
Bind<IRolesService>().To<AspNetRoleProviderWrapper>();
Bind<IUserService>().To<AspNetMembershipProviderWrapper>();
Bind<ICurrentUserSerivce>().To<DefaultCurrentUserSerivce>();
Bind<IPasswordService>().To<AspNetMembershipProviderWrapper>();
Bind<IStatusResponseRepository>().To<StatusResponseRepository>();
Bind<ICategoryRepository>().To<CategoryRepository>();
Bind<IProductRepository>().To<ProductRepository>();
}
}
You should be using the "one session per request" pattern, by storing the ISession object in the HttpContext and sharing it between repositories and queries made during the same HTTP request.
Here's an implementation using MVC action attributes.
An easy/basic implementation could also be achieved by simply altering your NHibernateHelper class like this:
public class NHibernateHelper {
//...
const string SessionKey = "NhibernateSessionPerRequest";
public static ISession OpenSession(){
var context = HttpContext.Current;
if(context != null && context.Items.ContainsKey(SessionKey)){
//Return already open ISession
return (ISession)context.Items[SessionKey];
}
else{
//Create new ISession and store in HttpContext
var newSession = SessionFactory.OpenSession();
if(context != null)
context.Items[SessionKey] = newSession;
return newSession;
}
}
}
Code hasn't been neither compiled nor tested... should work however.
Your code or, preferably, dependency injection should always pass the ISession into a repository's constructor. This allows multiple repositories to participate in a single transaction.
I second Paco's recommendation to let a dependency injection framework handle this for you. The challenge with this approach is with non-web applications that do not have clean unit-of-work boundaries like the HTTP request-response cycle. We have repositories that are shared by Windows Forms and ASP.NET applications and we manually manage newing up repositories in the Windows Forms applications.
Use an inversion of control container
Try using sessionFactory.GetCurrentSession() which will allow you to access a contextual session.
This will basically allow you to use the 'session per request' model as described in another answer, without having to code that yourself.
You can even choose what your context is: Http (as your example suggests) or a bunch of others too (I use CallSessionContext
for my unit test).
精彩评论