Entity Framework Context Lifetime Questions

asp.net-mvc c# entity-framework idisposable using

Question

In an ASP.NET MVC application, what is the ideal lifespan of an Entity Framework context? Isn't it preferable to preserve the context for as little time as possible?

Think about the controller action that follows:

public ActionResult Index()
{
    IEnumerable<MyTable> model;

    using (var context = new MyEntities())
    {
        model = context.MyTable;
    }

    return View(model);
}

The Entity Framework context has left its scope while the view is rendering the page, hence the code above will not function. How might others organize the aforementioned code?

1
22
4/20/2017 4:21:58 PM

Accepted Answer

Let's engage in some debate!

For a variety of reasons, I don't agree with the broad MVC + EF agreement that maintaining a context for the whole of the request is a good idea.

decrease in performance Do you have any idea how much it costs to create a new database context? Well, that's "The creation of a DataContext is inexpensive and lightweight." from "MSDN."

Once you go live, getting the IoC incorrect will first appear acceptable. If you configure your IoC container to dispose of your context on your behalf and you make a mistake, you really make a mistake. I've now twice observed enormous memory leaks caused by an IoC container that didn't always properly dispose of a context. Before your servers start failing under typical amounts of concurrent users, you won't realize you've configured it incorrectly. Run some load tests since it won't happen during development!

Inadvertently loading slowly In order to display your most current articles on your homepage, you return an IQueryable of them. One day another person is requested to display the quantity of comments next to the relevant content. So they just add the code the View to display the comment count in the manner shown...

@foreach(var article in Model.Articles) {
    <div>
        <b>@article.Title</b> <span>@article.Comments.Count() comments</span>
    </div>
}

Works and looks just nice. The comments weren't included in the data you actually supplied, thus this will now contact the database again for each item in the loop. Issue SELECT N+1. 11 database calls for 10 articles. Okay, so the code is incorrect, but because it is simple to create mistakes, they will occur.

By turning off your context in your data layer, you can avoid this. However, a NullReferenceException on the article won't cause the function to crash. Count() the comments? In order to get the information required for the View layer, you will be forced to alter the Data layer. This is how things ought to be.

Code odor Simply said, touching the database from your View is flawed in some way. You are aware that an IQueryable hasn't really been used to query the database, therefore disregard that object. Prior to leaving your data layer, ensure that your database has been accessed.

So, the response

In my view, your code ought to look like this.

DataLayer:

public List<Article> GetArticles()
{
    List<Article> model;

    using (var context = new MyEntities())
    {
        //for an example I've assumed your "MyTable" is a table of news articles
        model = (from mt in context.Articles
                select mt).ToList();
        //data in a List<T> so the database has been hit now and data is final
    }

    return model;
}

Controller:

public ActionResult Index()
{
    var model = new HomeViewModel(); //class with the bits needed for you view
    model.Articles = _dataservice.GetArticles(); //irrelevant how _dataService was intialised
    return View(model);
}

You shouldn't try to experiment with having an IoC container manage context until you have completed this and understood it. Please heed my caution as I've seen two significant failures:)

But in all honesty, do what you want; programming is enjoyable and should be a personal choice. I'm just sharing mine with you. However, under no circumstances should you begin utilizing IoC context for each controller or request just because "all the cool kids are doing it." Do it because you actually care about its advantages and are aware of how it should be carried out.

51
5/28/2012 10:06:24 AM

Popular Answer

I agree that we should only bind the context once for each request. InRequestScope, which is quite effective and uses Ninject

Bind<MyContext>().ToSelf().InRequestScope();

Additionally, it's a good idea to enumerate the set as closely as feasible to the query, for example:

public ActionResult Index()
{
    IEnumerable<MyTable> model;

    using (var context = new MyEntities())
    {
        model = (from mt in context.MyTable
                select mt).ToArray();
    }
    return View(model);
}

This will assist you in preventing inadvertent query augmentation from your point of view.



Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow