Why does “Dispose” work, and not “using(var db = n

2019-04-06 03:27发布

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.

4条回答
Emotional °昔
2楼-- · 2019-04-06 03:58

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.

查看更多
你好瞎i
3楼-- · 2019-04-06 04:00

You can't return view or something inside using context as this is causing problem disposing the context here.

correct way of using using statement in your case is

public ActionResult Topic(int id) //Topic Id
{
    Topic topic = null; // topic is your POCO
    using (var db = new DataContext())
    {
        topic = db.Topics.Include("Messages").Include("Messages.CreatedBy").Include("CreatedBy").FirstOrDefault(x => x.Id == id);   
    }
    return topic != null ? View(topic) : View();

}

also do not do response redirect if you in using statement..

see here : Disposing Database context with using statement in MVC

查看更多
戒情不戒烟
4楼-- · 2019-04-06 04:07

It was a problem with Lazy Loading, so thanks for the point in the right direction @Dismissile

Once I used '.Include' to load each virtual property of Topic, it worked fine:

var topic = db.Topics.Include("Messages").Include("Messages.CreatedBy").Include("CreatedBy").Include("Forum").Include("DeletedBy").FirstOrDefault(x => x.Id == id);

I guess it would have been impossible for anyone to know which properties I had declared as virtual without me saying, sorry!

Incidentally, it worked before when I was inspecting the properties in debug mode, because each property would have to be loaded for me to inspect it

查看更多
一纸荒年 Trace。
5楼-- · 2019-04-06 04:11

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.

查看更多
登录 后发表回答