Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does "Dispose" work, and not "using(var db = new DataContext())"?

I'm creating a forum which is made up of topics, which are made up of messages.

When I try to implement the topic View in my Controller with:

public ActionResult Topic(int id) //Topic Id
{
    using (var db = new DataContext())
    {
        var topic = db.Topics.Include("Messages").Include("Messages.CreatedBy").Include("CreatedBy").FirstOrDefault(x => x.Id == id);

        //include the messages for each topic, and when they were created so that the last message can be displayed on the topic page
        return topic != null ? View(topic) : View();
    }
}

I get this error when I try to view the topic page:

ObjectDisposedException was unhandled by user code

The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.

The error doesn't seem specific to a certain line, as when I remove the offending line, the same error apperars earlier on.

I have solved this by using:

DataContext db = new DataContext();

at the start of the controller and:

protected override void Dispose(bool disposing)
{
    db.Dispose();             
    base.Dispose(disposing);
}

at the end (and taking using out)

Although this works, I am curious as to why "Using" doesn't work, and I'm not really happy having the connection open throughout the controller, and disposing of it manually at the end.

like image 782
ECH Avatar asked Apr 16 '14 13:04

ECH


2 Answers

Do any of your entities have lazy loading enabled? It seems like there are queries getting executed in your views but you are disposing your context before they get executed (hence the error saying it is already disposed). If you put the disposal in the controller Dispose method, the view will get executed before the controller and context is disposed.

I recommend installing Glimpse.Mvc5 and Glimpse.EF6 packages. Once you configure glimpse you can see every query that gets executed in your page. You might be surprised to see a few additional queries get executed that you did not intend. This is why I don't recommend using entities directly in your views.

like image 174
Dismissile Avatar answered Oct 09 '22 02:10

Dismissile


This is happening because generally LINQ entities are proxy objects. If you have something like MyEntity.ChildEntities, the underlying SQL query isn't executed to fetch those objects until the code is executed. If you're accessing them in a view, the view isn't bound until after the action method returns, at which point the DbContext is already disposed.

The lifecycle looks something like this:

  1. Call action method
  2. The outer query to fetch the topic runs, but any additional accessors in the view that trigger more SQL queries are not executed yet.
  3. We've now left the action method, so using just disposed your DbContext.
  4. The MVC framework binds the model to the view, which triggers actually executing any remaining queries and fails since DbContext is disposed.
  5. The request lifecycle is about to end, so the controller is disposed.

Here's a good resource on lazy loading with entities.

like image 21
Rex M Avatar answered Oct 09 '22 03:10

Rex M