Почему "Dispose" работает, а не"using(var db = new DataContext ())"?

Я создаю форум, который состоит из разделов, которые состоят из сообщений.

когда я пытаюсь реализовать представление темы В моем контроллере с помощью:

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();
    }
}

Я получаю эту ошибку при попытке просмотреть страницу темы:

ObjectDisposedException был необработан кодом пользователя

экземпляр ObjectContext был удален и больше не может использоваться для операций, требующих соединение.

ошибка не кажется специфичной для определенной строки, так как, когда я удаляю оскорбительную строку, та же ошибка появляется ранее.

Я решил это, используя:

DataContext db = new DataContext();

в начале контроллера и:

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

в конце (и с using out)

хотя это работает, мне любопытно, почему "использование" не работает, и я не очень доволен тем, что соединение открыто по всему контроллеру, и утилизировать его вручную в конце.

4 ответов


У любого из ваших объектов включена ленивая загрузка? Похоже, что в ваших представлениях выполняются запросы, но вы избавляетесь от своего контекста, прежде чем они будут выполнены (следовательно, ошибка говорит, что она уже удалена). Если вы поместите удаление в метод Dispose контроллера, представление будет выполнено до удаления контроллера и контекста.

Я рекомендую установить Glimpse.Mvc5 и мельком.Ef6 в пакеты. После настройки glimpse вы можете видеть каждый запрос это выполняется на Вашей странице. Вы можете быть удивлены, увидев, что выполняется несколько дополнительных запросов, которые вы не намеревались. Вот почему я не рекомендую использовать сущности непосредственно в ваших представлениях.


это происходит потому, что обычно объекты LINQ являются прокси-объектами. Если у вас есть что-то вроде MyEntity.ChildEntities базовый SQL-запрос не выполняется для извлечения этих объектов до выполнения кода. Если вы обращаетесь к ним в представлении, представление не будет связано до тех пор, пока метод action не вернется, и в этот момент DbContext уже будет удален.

жизненный цикл выглядит примерно так:

  1. вызовите метод действия
  2. внешний запрос для выборки the topic выполняется, но любые дополнительные методы доступа в представлении, которые запускают больше SQL-запросов, еще не выполнены.
  3. теперь мы оставили метод действия, так что using просто утилизировал ваш DbContext.
  4. платформа MVC привязывает модель к представлению, которое фактически запускает выполнение любых оставшихся запросов и завершается ошибкой, так как DbContext удален.
  5. жизненный цикл запроса заканчивается, поэтому контроллер удален.

вот хороший ресурс по ленивой загрузке с сущностями.


Это была проблема с отложенной загрузки, так что спасибо за точку в правильном направлении @освобождающий лук

когда я использовал '.Включить " для загрузки каждого виртуального свойства темы, он работал нормально:

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

Я думаю, было бы невозможно для кого-либо узнать, какие свойства я объявил виртуальными без меня, извините!

кстати, он работал раньше, когда я проверял свойства в режиме отладки, потому что каждое свойство должно быть загружено для меня, чтобы проверить его


вы не можете вернуть представление или что-то внутри, используя контекст, поскольку это вызывает проблему с удалением контекста здесь.

правильный способ использования using утверждение в вашем случае

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();

}

также не делайте перенаправление ответа, если вы используете оператор..

смотрите здесь : удаление контекста базы данных с помощью оператора using в MVC