When to commit NHibernate transactions in ASP.NET MVC 2 application?

蹲街弑〆低调 提交于 2019-12-04 07:55:17

If you're using ASP.NET MVC, you could use an ActionFilter to achieve the same effect.

Something like (this is hacked together from difference pieces of my architecture):

public class TransactionalAttribute : ActionFilterAttribute, IAuthorizationFilter, IExceptionFilter
{

    ITransaction transaction = NullTransaction.Instance;
    public IsolationLevel IsolationLevel { get; set; } 

    public TransactionalAttribute() 
    {
        IsolationLevel = IsolationLevel.ReadCommitted;
    }

    public override void OnResultExecuted(ResultExecutedContext filterContext)
    {
        try
        {
            transaction.Commit();
            transaction = NullTransaction.Instance;
        }
        catch (Exception exception)
        {
            Log.For(this).FatalFormat("Problem trying to commit transaction {0}", exception);
        }

    }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (transaction == NullTransaction.Instance) transaction = UnitOfWork.Current.BeginTransaction(IsolationLevel);
    }

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        if (filterContext.Result != null) return;

        transaction.Commit();
        transaction = NullTransaction.Instance;
    }

    public void OnAuthorization(AuthorizationContext filterContext)
    {
        transaction = UnitOfWork.Current.BeginTransaction(IsolationLevel);
    }

    public void OnException(ExceptionContext filterContext)
    {
        try
        {
            transaction.Rollback();
            transaction = NullTransaction.Instance;
        }
        catch (Exception exception)
        {
            Log.For(this).FatalFormat("Problem trying to rollback transaction {0}", exception);
        }
    }

    private class NullTransaction : ITransaction
    {
        public static ITransaction Instance { get { return Singleton<NullTransaction>.Instance; } }

        public void Dispose()
        {

        }

        public void Commit()
        {
        }

        public void Rollback()
        {
        }
    }
}

Well after thinking about it and discussed it with coworkers I've come up with a solution that meets almost all my requirements.

I implemented the solution with my Java projects and it worked great. I'll just pust the idea so everybody can use it within any framework.

The solution consist in putting the commit call in the last line of the controller method, inside a try-catch block. If a constraint exception occurs you can get the name of the violated constraint. With the name you can tell the user exactly what went wrong. I used a properties file to store the message to show to the user wich constraint was violated. The keys of the properties file are the constraints names and the values are the constraint violation messages.

Yo can refactor the commit-handle_exception-find_constraint_message to a method, that's what I did.

For now it solves my problem of writing code to check database integrity and I believe it's pretty elegant with the constraint violation messages in a properties file. Now, I still don't like the idea that my controllers need to call the commit, but that's way better than writing integrity checks that the database already does.

I will continue to use a filter just like David Kemp said, just that the filter will only open the (n)hibernate session and the transaction, and then, at the end of the request, close the session.

Comments are more than welcome. Thanks.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!