Proper Session/DbContext lifecycle management

Most “heavy” object-relational mappers (ORMs) have an interface that provides more than just easy querying of the database. They also are implementations of two key patterns:

For NHibernate, this is the ISession interface, and for Entity Framework, this is the DbContext class. Because these two classes are implementations of the Unit of Work pattern, we need to consider this as we design the lifecycle of these ORM interfaces. Reviewing a Unit of Work, it:

Maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems.

99% of the problems I see with bad session management is not understanding the Unit of Work pattern. Unit of Work is all about defining a “business transaction” and from there tailoring your session management accordingly. I’ll refer to both the ISession and DbContext objects as a “session” to make it easier.

Most of the time, a “business transaction” should be the same as a “database transaction”, and I usually make these one and the same. From an user interaction of view, there’s an expectation of transaction around operations. Click a button, hit “save” are all expectations that an operation succeeds or fails, but not both. In short, our session and transaction boundaries should be:

  • For web applications, use a session per request
  • For thick-client applications, use session per operation/command

In fact, this is exactly what both NHibernate and Microsoft recommend in the documentation. Pretty simple, no? In a web application, a common way of achieving this is to scope a session to an HttpContext instance. You can use filters in MVC or Application events (BeginRequest/EndRequest) to begin/commit transactions. The key though is all code using a session needs to be using the same instance. This is why I typically use the container to control lifecycle – it’s far too easy to screw this up yourself, and far easier to test when your business logic is unconcerned with transactions.

Sessions and repositories

If you’re using a repository, you shouldn’t be opening or closing sessions/transactions. Business transaction boundaries are a concern of the application, not low-level services. Don’t do this:

public class FooRepository : IFooRepository
{
    public void Save(Foo foo)
    {
        using (ISession session = SessionFactory.GetSession())
        {
            session.BeginTransaction();
            session.SaveOrUpdate(foo);
            session.Transaction.Commit();
        }
    }
    
    public void Delete(Foo foo)
    {
        using (ISession session = SessionFactory.GetSession())
        {
            session.BeginTransaction();
            session.Delete(foo);
            session.Transaction.Commit();
        }
    }
    
    public Foo Get(Guid id)
    {
        using (ISession session = SessionFactory.GetSession())
        {
            return session.Get<Foo>(id);
        }
    }
}

Consumers of your repository don’t know that you’re opening and closing sessions, nor should they. It’s completely non-obvious and potentially nasty behavior. If a user calls “Save” twice and then “Delete” in the context of one business operation, “Delete” could fail but the two “Save” calls succeed! Very nasty behavior, indeed! Even if we merely open/close sessions for reads (I’ve seen this done to prevent lazy-loading), it’s still not obvious and prevents us from using the Unit of Work and Identity Map functionality. Again, not a good idea.

Instead, our repository should merely consume a session:

    public class FooRepository : IFooRepository
    {
        private readonly ISession _session;
        
        public FooRepository(ISession session)
        {
          _session = session;
        }
        
        public void Save(Foo foo)
        {
          session.SaveOrUpdate(foo);
        }
        
        public void Delete(Foo foo)
        {
          session.Delete(foo);
        }
        
        public Foo Get(Guid id)
        {
          return session.Get<Foo>(id);
        }
    }

Control of the business transaction is restored back to the application.

In short, a session represents a unit of work, a unit of work represents a business transaction, and a business transaction almost always represents a user interface operation. Tailor your session lifecycle around user interface operations (requests for web, commands for thick client) and your ORM will give you predictable, obvious results.

Related Articles:

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Jimmy Bogard

I'm a technical architect with Headspring in Austin, TX. I focus on DDD, distributed systems, and any other acronym-centric design/architecture/methodology. I created AutoMapper and am a co-author of the ASP.NET MVC in Action books.
This entry was posted in Architecture, Patterns. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • jeremydmiller

    Nice post as usual, but I’d strongly recommend using IoC features like StructureMap’s nested container per web request in place of any kind of scoping that relies on HttpContext.

    • jbogard

      Dude, blog that stuff.

      • KennyBu

        +1 for a blog post by jeremydmiller to demonstrate that!

    • kamranayub

      Is this different than say, Ninjects “InRequestScope” scope?

    • AlexanderTank

      Why nested container instead of HttpContextScoped configuration?

    • Josh Rogers

      I am reviewing your previous blog posts in regards to nested containers( http://codebetter.com/jeremymiller/2010/02/10/nested-containers-in-structuremap-2-6-1/ ), but I am truly failing to see how to implement this within the context of Web API for example. I have to second @jbogard:disqus in asking for a blog post on this with some examples.

      • jeremydmiller

        Well, step #1 is to use FubuMVC instead of Web API where the nested container mechanics are built in;)

        In Web API this kind of thing is done w/ the IDependencyScope abstraction exposed by their IDependencyResolver interface. I don’t know if anyone has built an SM resolver for WebAPI that does that yet.

        And yes, I’ll get around to a blog post on this topic soon-ish.

  • kamranayub

    Yes, I typically use Ninject’s InRequestScope for my DbContext instance. Works pretty well!

  • Mike Cole

    This is not a complicated subject (it gets more complicated in a thick-client app), but so many people mess it up.

  • Brent Krueger

    It’s difficult to understand these concepts at first when working with an ORM but I think you did a good job of clearly, concisely explaining these session management patterns. Very easy to understand, thank you! I will refer anyone with nHibernate session per request questions to this post from now on.

    • jbogard

      Thanks!

  • Matthew Fitchett

    Nice post. All feels ‘obvious’ but one of those things that’s very easy to not quite understand and easy to get wrong!

    How about something like NServiceBus where there’s an ambient transaction to consider as well? Should the container be concerned with ensuring the session or UOW that’s passed to repo’s is correctly enlisted?

    I’ve also found edge cases where you may want to log failures/statuses inside such an ambient transaction to require more granular transaction control.

    • jbogard

      With NServiceBus I scope the unit of work to the handler scope. Since NServiceBus has an IManageUnitsOfWork extension, that’s where you can do session management.

  • AlexanderTank

    Isn’t there a big difference between per web request and per ASP.NET MVC action?
    In my opinion within one web request you can invoke multiple actions. So isn’t it a bad idea to use ASP.NET MVC Action Filters?

    • jbogard

      Yeah, though you can check that inside your filter to know you’re in a child action or not. I usually go for the application level myself.

  • http://aashishkoirala.github.io/ Aashish Koirala

    Isn’t this just Unit-of-Work 101?

    • jbogard

      Yes :) but lots of folks that use these tools don’t know what that term means, or how it affects your design.

  • Mike Cole

    What about calling SaveChanges or flushing your session? At the end of the UoW + whenever else needed manually?

  • craigsmitham

    I’ve seen some take this approach farther and have the session injected into services that perform business operations. At what point do you draw the line where you service contracts should be session-ignorant?

    • jbogard

      Oh, I didn’t mean services shouldn’t use a session, but that they shouldn’t be futzing with transactions or units of work. That’s handled at the boundary layers. They can use the unit of work, but not manage them.

      • Trubar

        I’m new to design patterns and architecture, so I apologize for any dumb questions. Anyways, what are boundary layers?

        • jbogard

          Boundary layers are layers at the boundary of code that you own and code that you don’t. The UI layer, for example.

  • http://damienbod.wordpress.com/ Damien

    Nice post, thanks, I do it the same way using Unity 3 IoC which also provides a per request lifecycle manager

    thanks for the post greetings Damien

  • Rui Jarimba

    Hi Jimmy,

    Shouldn’t your FooRepository implement IDisposable and in the Dispose() method you would dispose the ISession or DbContext?

    Thanks,
    Rui

    • Mike Cole

      This actually is a perfect example of what the article is discouraging.

      • Rui Jarimba

        I was thinking of the disposal of the Session/DbContext, not managing database connections. I don’t know how NHibernate works but using EF you don’t usually have to worry about managing connections, I’m assuming the NHibernate works the same way. Maybe I’m missing the point, it would help to see how the DbContexts and repositories are instantiated, used and disposed.

        • jbogard

          All with the container. All instantiated once at the beginning of a web request and shared throughout the lifetime of that request, disposed at the end.

  • Trubar

    It seems you’re against explicitly implementing UoW pattern ( by “explicitly” I mean introducing a IUnitOfWork interface ). But seeing how a particular web request can invoke multiple Asp.Net MVC actions, there may be cases where a particular action within such request should have its own transactional boundary. Is there any other way to handle this other than introducing IUnitOfWork interface?

    • jbogard

      If I need my own transactional boundary, I’ll likely just create a new transaction. I’m not against IUnitOfWork, I’ve just moved away from it because ultimately I need to understand *exactly* what the implementation does in order to use one.

      • Trubar

        Sorry for being a pest. Anyways, final questions. 1 – When you begin/commit the transaction ( within BeginRequest/EndRequest or within MVC action ), do you call begin/commit directly on the context ( in which case you’re violating persistence ignorant rule ) or do you make the calls to begin/commit transaction in a persistence ignorant manner? If the latter, how if not via IUnitOfWork? 2 – “I need to understand *exactly* what the implementation does in order to use one” Could you elaborate on what you mean by ” understand exactly what the implementation does”? Perhaps that each transaction has its own little peculiarities and thus each transaction should be dealt with individually and not via common code ( by “common code” I’m referring to UnitOfWOrk implementation )?

        • jbogard

          What is this “persistence ignorance” rule? The way I manage Begin/Commit is just in the global.asax, grabbing an instance of ISession and calling BeginTransaction, then Commit/Rollback in EndRequest.

          As for some actions needing their own transaction, I just handle that explicitly by creating a new transaction from ISession wherever I need to do so. And by Unit of Work management, I wasn’t really talking about how one should abstract the existing ORM into a Unit of Work interface, I don’t do that.

          • Mickael

            Hey Jimmy,

            Nice post, as usual, very useful.
            Do you see anything bad in managing transactions/commits for the UoW directly with the IoC container? They usually expose OnCreated/OnRelease events, which, as you scope a UoW by HTTP request, achieve the same thing if I’m not mistaken.

          • jbogard

            You know, it really depends on what I’m hosting under. But I do typically do this in my application, because I might need to have custom logic to deal with failures.

    • Mike Cole

      This is how I handle it. There are times I need to explicitly commit so I can return IDs or other database generated items.

      • jbogard

        Gotcha. I should have prefaced that because I’m using an ORM that generates my IDs, I don’t need to do anything explicit.

  • Japjeet Singh

    Nice Post. In your post you said.

    “For thick-client applications, use session per operation/command”. Wouldn’t that mean that you have to open and close the context per request to the repository as shown in the first code image? Otherwise wouldn’t it become a problem when using say WPF clients that store data locally and update them from the internet.?

    • jbogard

      Long-lived entities is a problem no matter what – I tend to use view models that have read-only versions of entities, then self-contained commands that encapsulate their own unit of work.

      • Mike Cole

        Is this where a person would use ThreadLocal scope in StructureMap? I’ve never implemented it successfully.

        • jbogard

          It does seem strange, nested containers seem like a much better solution.

          • Mike Cole

            I need to do some learning on nested containers.

  • internetshop111

    nice.. deep information

  • jxxs

    I am beginning to wonder if ANYONE uses NHibernate with a WPF or Win Forms application, such is teh dearth of examples or text books on the subject. I am struggling to find “best practices” for its use, and especially session and sessionfactory management, with an MVVM WPF application and repositories. Your post above is a very clear pointer and helps a lot. But, with the session being outwith the repository, and therefore, I assume, in the View Model, does this not create a dependency between the VM and NHibernate, i.e. between the VM and a particular persistence method? Maybe this is just unavoidable and not necessarily evil in any way. This (http://nhibernatewpf.codeplex.com/) is quite a good example (no repos as such) and certainly there is a tight link between the VM and NH.
    Any comments on this WPF (i.e. non-http) context would be welcome!