I'm letting Ninject manage my ISession
and ITransaction
state in Fluent nHibnerate with the following registration method - I am wondering if it is sufficient control of transactions, or whether I need to be putting this somewhere else.
The thought is that each ISession
is created on a request, and that Ninject handles the commit of everything done during that request.
public class SessionModule : Ninject.Modules.NinjectModule
{
private static ISessionFactory sessionFactory;
public override void Load()
{
Bind<ISessionFactory>()
.ToMethod(c => CreateSessionFactory())
.InSingletonScope();
Bind<ISession>()
.ToMethod(c => OpenSession())
.InRequestScope()
.OnActivation(session =>
{
session.BeginTransaction();
session.FlushMode = FlushMode.Commit;
})
.OnDeactivation(session =>
{
if (session.Transaction.IsActive)
{
try
{
session.Flush();
session.Transaction.Commit();
}
catch
{
session.Transaction.Rollback();
}
}
});
}
/// <summary>
/// Create a new <see cref="NHibernate.ISessionFactory"/> to connect to a database.
/// </summary>
/// <returns>
/// A constructed and mapped <see cref="NHibernate.ISessionFactory"/>.
/// </returns>
private static ISessionFactory CreateSessionFactory()
{
if (sessionFactory == null)
sessionFactory = Persistence.SessionFactory.Map
(System.Web.Configuration
.WebConfigurationManager
.ConnectionStrings["Local"]
.ConnectionString
);
return sessionFactory;
}
/// <summary>
/// Open a new <see cref="NHibernate.ISession"/> from a <see cref="NHibernate.ISessionFactory"/>.
/// </summary>
/// <returns>
/// A new <see cref="NHibernate.ISession"/>.
/// </returns>
private static ISession OpenSession()
{
// check to see if we even have a session factory to get a session from
if (sessionFactory == null)
CreateSessionFactory();
// open a new session from the factory if there is no current one
return sessionFactory.OpenSession();
}
}
I've examined the runtime using System.Diagnostics.Debug.WriteLine
to write when things occur, and it does look like this is doing what I wanted it to do. What I am asking you, the community, is whether this is a good practice or not. Here is my understanding.
Countless hours of reading on http://ayende.com/blog/default.aspx has led me to re-evaluate a lot of the way I do session management.
A lot of digging into the nHibernate documentation tells me I need to use ITransaction
every single time anything happens with my database.
Placing the management in an attribute is considered a flaw, since it does not adhere to the above mentioned statement.
Doing ITransaction
per individual operation is not the correct process, because it would require either (A) my Controllers to have access to the ISession
or (B) My IRe开发者_开发知识库pository<T>
to have the ITransaction
logic, which I have been told in previous questions was not a good practice.
Placing my ITransaction
Management in an HttpModule
adds un-neccessary overhead, since it gives my HttpContext knowledge of the ISession
and it means I have to do some kind of injection into the HttpRequest
(which I can do using [Inject]
, but it doesn't seem wise)
This has led me to this conclusion.
- Transactions should start when an
ISession
is requested. - Everything that happens in a single request is encapsulated by one
ISession
- When an
ITransaction
is done, it needs to be committed so that the 2nd Level Cache can get its results.
Can anyone shed light on this? Am I finally on the right track? Or have I still missed the point completely?
I'm no expert (and have no experience with ninject), but I do agree with your 3 conclusions, and that's what I do in my projects.
Another thing I can add is that, in my opinion, transactions should be controlled EXPLICITLY and per operation, and not globally (start and beginning of request and commit at the end) like your code suggests.
This is because I believe you want to control your transaction's behaviour- commit or not (or maybe not even start, if no DB access is necessary) for every operation individually.
What I use is a management (or workflow, if you prefer) layer, which is responsible just for that. for example:
public class SomeManager : ManagersBase
{
public void DoSomething(DomainObject obj)
{
if (obj.Operation())
{
using (ITransaction tx = Session.BeginTransaction())
{
try
{
Session.Update(obj);
tx.Commit();
}
catch (MeaningfulException ex)
{
//handle
tx.Rollback();
}
}
}
}
}
hope this helps
精彩评论