NHibernate Sessions + Transactions Using ASP.NET MVC 3

I am writing a new application at the moment, although the standard of the company is to use NHibernate (because this standard is for all projects), and instead I use ASP.NET MVC 3 because of its maturity now. I implemented my transactions in controllers (which is supposedly the way you should do this), so this looks like in my root controller:

[TransactionPerRequest]
public class FbsController : Controller
{

}

Then all my controllers inherit from this FbsController. The reason for this is that 90% of all my actions will be sent to the database, so the overhead of creating a transaction and ordering it for the remaining 10% of the actions (which will rarely be performed) are not worth decorating every action [TransactionPerRequest].

What has always offended me relates to NHibernate sessions. In repository classes, this is similar to what I have, although in other projects this is different:

    public void Add(User user)
    {
        using (ISession session = NHibernateHelper.OpenSession())
        {
            session.Save(user);
        }
    }

    public void Remove(User user)
    {
        using (ISession session = NHibernateHelper.OpenSession())
        {
            session.Delete(user);
        }
    }

    public User GetById(int userId)
    {
        using (ISession session = NHibernateHelper.OpenSession())
        {
            return session.QueryOver<User>()
                .Where(c => c.UserID == userId)
                .SingleOrDefault();
        }
    }

So, for most of the functions in my repository, I need to open a session. Is there a way to avoid this behavior, so I don’t need to open a session inside each repository method? This seems a bit controversial, as I usually have to do this for everyone. I was curious that all the other solutions were related to the transaction and session problem that I see clogging up the code in different ways.

Actually, I want my repository methods to look like this:

    public void Add(User user)
    {
        session.Save(user);
    }

    public void Remove(User user)
    {
        session.Delete(user);
    }

    public User GetById(int userId)
    {
        return session.QueryOver<User>()
            .Where(c => c.UserID == userId)
            .SingleOrDefault();
    }

Everything that is implicitly.

+3
source share
3 answers

You can take a look at the following series of blog posts by Ayende Rahien:

+10

- :

Global.asax.cs:

public static ISessionFactory SessionFactory { get; set; }

Application_Start:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    RegisterRoutes(RouteTable.Routes);

    var nhConfig = new Configuration().Configure();
    SessionFactory = nhConfig.BuildSessionFactory();
}

:

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class NHSession : ActionFilterAttribute
{
    public NHSession()
    {
        Order = 100;
    }

    protected ISessionFactory sessionFactory
    {
        get
        {
                return MvcApplication.SessionFactory;
        }
    }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var session = sessionFactory.OpenSession();
        CurrentSessionContext.Bind(session);
        session.BeginTransaction();
    }

    public override void OnResultExecuted(ResultExecutedContext filterContext)
    {
        var session = CurrentSessionContext.Unbind(sessionFactory);
        if (session != null)
        {
            if (session.Transaction.IsActive)
            {
                try
                {
                    session.Transaction.Commit();
                }
                catch
                {
                    session.Transaction.Rollback();
                }
            }
            session.Close();
        }
    }
}

:

public class Repository<T> : IRepository<T>
{
    private readonly ISessionFactory SessionFactory;
    public Repository(ISessionFactory sessionFactory)
    {
        SessionFactory = sessionFactory;
    }
    public ISession Session
    {
        get
        {
            return SessionFactory.GetCurrentSession();
        }
    }
    public T Get(long id)
    {
        return Session.Get<T>(id);
    }
}

:

public class CmsContentRepository : Repository<CmsContent>, ICmsContentRepository
{
    public CmsContentRepository(ISessionFactory sessionFactory) : base(sessionFactory) { }
}

, , :

[NHSession]
public ViewResult Revisions(int id)
{
    var model = Service.CmsContentRepository.Get(id);
    return View("Revisions", model);
}

. , SessionFactory (). DI , . , , . NHProf, ( , ).

+4

StructureMap ISession, HttpRequest. .

, , Fluent NHibernate StructureMap.

public class Bootstrapper
{
    public static ISessionFactory DBSessionFactory { get; set; }
    public static ISession DBSession { get; set; }

    public static void InitializeObjectFactory()
    {
        ObjectFactory.Initialize(x =>
                                     {
                                         x.PullConfigurationFromAppConfig = true;
                                         x.Scan(y =>
                                                    {
                                                        y.Assembly(Assembly.GetAssembly(typeof(AccountController)));
                                                        y.Assembly(Assembly.GetAssembly(typeof(IMyProject)));
                                                        y.WithDefaultConventions();
                                                    }
                                             );

                                         // these are for NHibernate
                                         x.ForRequestedType<ISessionFactory>()
                                             .CacheBy(InstanceScope.Singleton)
                                             .TheDefault.Is.ConstructedBy(GetDBSessionFactory);

                                         // open session at beginning of every http request 
                                         // (the session is disposed at end of http request in global.asax Application_EndRequest)
                                         x.ForRequestedType<ISession>()
                                             .CacheBy(InstanceScope.HttpContext)
                                             .TheDefault.Is.ConstructedBy(GetDBSession);
                                     });
    }

    public static ISessionFactory CreateSessionFactory()
    {
        return GetFluentConfiguration()
            .BuildSessionFactory();
    }

    public static ISessionFactory GetDBSessionFactory()
    {
        if (DBSessionFactory == null)
        {
            DBSessionFactory = CreateSessionFactory();
        }
        return DBSessionFactory;
    }

    public static ISession GetDBSession()
    {
        if (DBSession == null)
        {
            DBSession = CreateSession();
        }
        return DBSession;
    }

    public static ISession CreateSession()
    {
        return GetDBSessionFactory()
            .OpenSession();
    }

    public static FluentConfiguration GetFluentConfiguration()
    {
        string commandTimeout = ConfigurationManager.AppSettings["MyDBCommandTimeout"];
        return Fluently.Configure()
            .Database(// use your db configuration )
            .Mappings(m =>
                          {
                              m.HbmMappings
                                  .AddFromAssemblyOf<MyEO>();
                              m.FluentMappings
                                  .AddFromAssemblyOf<MyEO>()
                                  .AddFromAssemblyOf<MyEOMap>();
                          })
            .ExposeConfiguration(
                cfg =>
                    {
                        // command_timeout sets the timeout for the queries
                        cfg.SetProperty("command_timeout", commandTimeout);
                    }
            );
    }
}

Call Bootstrapper.InitializeObjectFactory (); in the Application_Start () method in your global.asax, for example:

protected void Application_Start()
{
    RegisterRoutes(RouteTable.Routes);
    Bootstrapper.InitializeObjectFactory();
    ...
}

Close the session in Application_EndRequest ():

protected void Application_EndRequest()
{
    // ensure that we aren’t leaking ISessions on every web request
    if (Bootstrapper.DBSession != null)
    {
        if (Bootstrapper.DBSession.IsOpen)
        {
             Bootstrapper.DBSession.Close();
        }
        Bootstrapper.DBSession.Dispose();
        Bootstrapper.DBSession = null;
    }

    HttpContextBuildPolicy.DisposeAndClearAll();
}

Now you just call

ObjectFactory.GetInstance<ISession>() 

from anywhere (I am moving it to a helper class so that my code is simple) and StructureMap will provide you with your cached session.

0
source

All Articles