When using the entity framework with a data context we often have this problematic:
What’s the best between performance and simplicity of usage or scalability?
(no? you do not ask yourself that kind of existential question?)
Here is a little explanation :
Static instance
In this first case you wrote a static reference to the context. Sometimes you also add some lazy loading and/or disposal management in global.asax (application end event)
It is efficient (understand fast) because the context is instantiated at the same time as the application domain (when app pool starts) or during the first call.
The instance will be destroyed during application end/stop (iis reset, pool reset, etc)
The advantage resides in the fact that, for each page request the model is already in memory. Entity Framework does not have to re scheme the model in memory and to check model and database integrity.
Another advantage is that you are working with a unique instance of the context all along page generation. Your objects are related to the context (no context rebinding, navigation properties available…)
The problem is this instance is shared across the application domain. Shared across all requests. This can be source of troubles when using transactions but the most important, it can be a bottleneck. Indeed, the Entity Framework is a APU (Applicative Persistence Unit) which does not (or does a very little of) pool database connections.
One instance = limited connection = thread waiting.
Instance by call
In that case, context is instantiated every time we need it and disposed as soon as possible. If we have a business layer, the context is instantiated in each service method. Most of a time a using (){} block is used.
The advantage is the application uses multiple context instances, so the application easily scales up.
The inconvenient is we are working with disconnected entities, we have to attach entities to the context. We also have to explicitly ask navigation properties loading (via .Include() method). Things are more complicated.
Instance by Request
The solution Brian Knoepfel (coworker) and I found is the following one: instantiate one context for the request duration. So we benefit of the best of the two other solutions: simplicity, performances and scalability.
During Init we register an event which will be raised every time request handling ends.
Every time a new request is submitted, we instantiate a new entity framework context and store it into http context (unique to each request and in memory stored).
When we need the context we can access it via a simple helper.
During the end request event, we dispose the context avoiding potential memory leaks.
I hope this solution will help you building your applications. Do not hesitate to comment if you have a better one.
public class Global : System.Web.HttpApplication
{
public override void Init()
{
EndRequest += Global_EndRequest;
base.Init();
}
protected void Application_BeginRequest(object sender, EventArgs e)
{
HttpContext.Current.Items["EntityFrameworkContext"] = new AppEntitiesContext();
}
protected void Global_EndRequest(object sender, EventArgs e)
{
BLL.ContextHelper.RequestContext.Dispose();
}
public class ContextHelper
{
public static AppEntitiesContext RequestContext
{
get
{
return (AppEntitiesContext)HttpContext.Current.Items["EntityFrameworkContext"];
}
}
}
}