Problem
I’ve been reading a lot of articles about how to utilize various DI frameworks to set up Entity Framework’s DbContext so that just one is produced and used each HTTP web request.
Why is this a good concept to begin with? What are the benefits of using this approach? Is there any circumstance in which this would be a good idea? Is there anything you can do with this method that you can’t do with DbContexts instantiated per repository method call?
Asked by Andrew
Solution #1
Let me begin by agreeing with Ian: Using a single DbContext for the entire application is a Bad Idea. Only when you have a single-threaded application and a database that is only used by that single application instance does this make sense. The DbContext is not thread-safe, and because it caches data, it becomes stale quickly. When many users/applications operate on the database at the same time, this will get you into a lot of difficulty (which is very common of course). But I assume you already know that and are simply curious as to why not simply inject a fresh instance (i.e. with a temporary lifestyle) of the DbContext into everybody who requires it. (for additional explanation on why a single DbContext -or -or -or -or -or -or -or -or –
To begin, I’d want to point out that while registering a DbContext as temporary might work, you’re more likely to desire a single instance of such a unit of work within a certain scope. A Per Web Request lifestyle can be useful in a web application because it is possible to set such a scope on the bounds of a web request. This allows you to use a single context for a large number of objects. To put it another way, they are both involved in the same business transaction.
If you don’t care about having a set of operations run in the same environment, the nomadic lifestyle is great, but there are a few factors to keep in mind:
Another solution is to just not inject a DbContext. You should instead inject a DbContextFactory that can build a new instance (I used to use this approach in the past). The context is explicitly controlled by the business logic in this way. This is what it might look like:
public void SomeOperation()
{
using (var context = this.contextFactory.CreateNew())
{
var entities = this.otherDependency.Operate(
context, "some value");
context.Entities.InsertOnSubmit(entities);
context.SaveChanges();
}
}
The advantage is that you can directly manage the DbContext’s lifecycle, and it’s simple to set up. It also allows you to use a single context in a specific scope, which has obvious benefits such as allowing you to run code in a single business transaction and passing entities around because they all come from the same DbContext.
The disadvantage is that you’ll have to pass the DbContext around from method to method (which is termed Method Injection). This solution is similar to the’scoped’ approach in that the scope is now controlled in the application code itself (and is possibly repeated many times). It is the application that is in charge of establishing and destroying the work unit. Constructor Injection isn’t an option because the DbContext is created after the dependence graph is built, therefore you’ll have to rely on Method Injection to transmit the context from one class to the next.
Method injection isn’t awful, but if the business logic becomes more sophisticated and more classes are involved, you’ll have to pass it from method to method and class to class, which can add a lot of complexity to the code (as I’ve seen before). However, for a small application, this strategy will suffice.
Because of the drawbacks of the factory technique for larger systems, another option, letting the container or infrastructure code / Composition Root manage the unit of work, can be useful. This is the style you’re referring to in your query.
Allowing the container and/or infrastructure to do this frees up your application code from having to construct, commit, and dispose of a UoW object, keeping the business logic simple and clear (just a Single Responsibility). There are some drawbacks to this strategy. Where do you Commit and Dispose the instance, for example?
A unit of work can be disposed of at the end of a web request. Many people, however, mistakenly believe that this is also where the unit of work is committed. However, at that point in the application, it’s impossible to know for sure whether or not the unit of work should be committed. You definitely don’t want to Commit if the business layer function threw an exception that was caught further up the callstack.
The real solution is to maintain some form of scope directly once more, but this time inside the Composition Root. You’ll be able to construct a decorator that wraps around each command handler and allows you to achieve this by abstracting any business logic behind the command / handler pattern. Example:
class TransactionalCommandHandlerDecorator<TCommand>
: ICommandHandler<TCommand>
{
readonly DbContext context;
readonly ICommandHandler<TCommand> decorated;
public TransactionCommandHandlerDecorator(
DbContext context,
ICommandHandler<TCommand> decorated)
{
this.context = context;
this.decorated = decorated;
}
public void Handle(TCommand command)
{
this.decorated.Handle(command);
context.SaveChanges();
}
}
This ensures that the infrastructure code is only written once. You can configure such a decorator to be wrapped over all ICommandHandlerT> implementations in a consistent manner in any solid DI container.
Answered by Steven
Solution #2
Microsoft makes two contradictory recommendations, and many individuals utilize DbContexts in very different ways.
Those contradict each other because your DbContext is stored for no purpose if your Request is doing a lot of irrelevant Db things. As a result, keeping your DbContext alive while your request is just waiting for random things to happen is a waste…
Many individuals that follow rule 1 keep their DbContexts in their “Repository pattern” and build a new Instance for each Database Query, resulting in X*DbContext per Request.
They simply obtain their data and rid of the context as quickly as possible. Many individuals regard this to be a perfectly acceptable practice. While this has the advantage of using your database resources for the shortest amount of time, it plainly compromises all of EF’s UnitOfWork and Caching goodies.
Keeping a single multifunctional DbContext instance alive optimizes the benefits of caching, however because DbContext is not thread safe and each Web request runs on its own thread, the longest you can keep it alive is a DbContext per Request.
So the EF team’s proposal to use one Db Context per request is clearly predicated on the idea that in a Web Application, a UnitOfWork will most likely be contained within a single request with a single thread. As a result, the ideal benefit of UnitOfWork and Caching is one DbContext per request.
However, this is not always the case. Having a new DbContext for Post-Request Logging on async threads is perfectly okay to me because I consider logging to be a separate UnitOfWork.
Finally, it appears that the lifespan of a DbContext is limited to these two parameters. Thread and UnitOfWork
Answered by Anestis Kivranoglou
Solution #3
There isn’t a single response that actually answers the question. The OP did not inquire about a singleton/per-application DbContext design; rather, he inquired about a per-(web)request design and what benefits could be available.
Because Mehdi is a terrific resource, I’ll mention http://mehdi.me/ambient-dbcontext-in-ef6/:
Keep in mind that there are disadvantages as well. There are many more resources on the issue at that link.
Just in case someone else comes across this question and isn’t distracted by answers that don’t actually answer the issue, I’m publishing this.
Answered by user4893106
Solution #4
I’m quite sure it’s because the DbContext isn’t thread safe at all. As a result, distributing the item is never a good idea.
Answered by Ian
Solution #5
The fact that DbContext cannot cancel modifications isn’t really addressed in the question or the conversation. You may submit modifications but not clear the change tree, thus if you utilize a per request context and need to discard changes for whatever reason, you’re out of luck.
Personally, I generate DbContext instances as needed, usually to attach to business components that can recreate the context if necessary. Instead of being obliged to use a single instance, I have control over the process. I also don’t have to create the DbContext every time the controller starts up, regardless of whether it’ll be needed. If I still require per-request instances, I can either construct them in the CTOR (through DI or manually) or in each controller method as needed. Personally, I prefer the latter approach because it allows me to avoid creating DbContext instances when they aren’t required.
It also depends on whatever way you look at it. Per-request instances have never made sense to me. Is it true that the DbContext belongs in the Http Request? That’s the incorrect place to be in terms of behavior. Your context should be created by your business components, not by the Http request. Then you can develop or discard your business components as needed, without having to worry about the context’s lifespan.
Answered by Rick Strahl
Post is based on https://stackoverflow.com/questions/10585478/one-dbcontext-per-web-request-why