Утилизация контекста EntityFramework

Я написал несколько приложений, которые работают с инфраструктурой сущностей. Раньше я работал с предложением using. С этим пунктом я уверен, что соединение с базой данных закрыто должным образом.

Но в некоторых случаях мой объект контекста базы данных является полем класса. Его реализация находится в объявлении, и нет предложения использования.

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

Итак, мой вопрос: что произойдет, если Dispose() не вызывается в контексте базы данных? Деструктор вызывается, так что вы думаете, что база данных будет закрыта деструктором? Или я должен вызвать Dispose() вручную в деструкторе объекта-контейнера следующим образом:

class MyClass
{
    public MyDbContext ctx = new MyDbContext();

    ....

    ~MyClass()
    {
         ctx.Dispose();
    }
}

Спасибо


person Bob5421    schedule 16.09.2016    source источник


Ответы (2)


Вы не должны звонить Dispose вообще. Специально explicitly.

Когда вы используете using, это implicit Dispose() в блоке try-finally. Это нормально. Но вам не нужно этого делать explicitly.

Почему?

Оператор separate или explicit Dispose can be missed, когда exception происходит earlier. Таким образом, нет никакой гарантии относительно explicit Dispose.

Вот это от Rowan Miller [MSFT]:

Поведение DbContext по умолчанию заключается в том, что базовое соединение автоматически открывается в любое время, когда это необходимо, и закрывается, когда оно больше не нужно. Например. когда вы выполняете запрос и выполняете итерацию по результатам запроса с помощью «foreach», вызов IEnumerable.GetEnumerator() приведет к открытию соединения, а когда позже больше не будет доступных результатов, «foreach» позаботится о вызове Dispose на перечислителе, который закроет соединение. Аналогичным образом вызов DbContext.SaveChanges() откроет соединение перед отправкой изменений в базу данных и закроет его перед возвратом.

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

Тем не менее, есть две основные причины, по которым наш пример кода имеет тенденцию всегда использовать «using» или размещать контекст каким-либо другим способом:

  1. Поведение автоматического открытия/закрытия по умолчанию относительно легко переопределить: вы можете взять на себя управление открытием и закрытием соединения, открывая соединение вручную. Как только вы начинаете делать это в какой-то части своего кода, то забывание о размещении контекста становится вредным, потому что вы можете пропускать открытые соединения.

  2. DbContext реализует IDiposable в соответствии с рекомендуемым шаблоном, который включает предоставление виртуального защищенного метода Dispose, который производные типы могут переопределить, если, например, необходимо объединить другие неуправляемые ресурсы в течение времени существования контекста.

Подробнее об этом можно прочитать здесь: Должен ли я всегда вызывать Dispose() для своих объектов DbContext? Нет

Правильное управление DbContext с помощью Entity Framework

person Sampath    schedule 16.09.2016
comment
Просто замечание: когда я пытаюсь... наконец, dispose не вызывается автоматически? Так что сделай больше, чем попробуй наконец - person Bob5421; 16.09.2016
comment
да, конечно. но это происходит внутри try,finally block implicitly. это другое, когда вы используете его explicitly. Вот почему нехорошо называть dispose explicitly. Нет гарантии. - person Sampath; 16.09.2016
comment
Хорошо, спасибо, а вы не знаете, есть ли способ установить постоянную связь с базой данных с EF? Я разработчик PHP старой школы, и мы использовали постоянное соединение, возможно, совместно используемое между несколькими HTTP-запросами для повышения производительности. Есть ли такой же способ в ASP.Net MVC С#? - person Bob5421; 16.09.2016
comment
При работе с Web applications используйте context instance per request. Это наилучший способ. Я разместил ссылку на него в своем посте. Пожалуйста, прочтите его для получения дополнительной информации. - person Sampath; 16.09.2016
comment
@Sampath Похоже, вы не делаете разницы между «не нужно» и «не должно» или «очень плохо». Единственная правда в этом посте содержится во вставленном тексте из связанного поста, то есть в большинстве случаев нет необходимости вызывать DbContext.Dispose. Все остальное о неявном и явном - это только ваше личное мнение. Нет ничего плохого в том, чтобы вызывать метод любого одноразового объекта Dispose explicity столько раз, сколько пожелаете. - person Ivan Stoev; 16.09.2016
comment
Я предоставил эту информацию в соответствии с контекстом OP. Это означает, что мы рассматриваем сценарий DbContext. Утверждение separate или explicit Dispose может быть пропущено, когда exception происходит раньше. Вот почему это плохо. На этот счет нет никаких гарантий. @IvanStoev - person Sampath; 17.09.2016

Если вы можете использовать using в своем родительском классе, сделайте так, чтобы он реализовал IDisposable:

class MyClass : IDisposable
{
    public MyDbContext ctx = new MyDbContext();

    ....

    public void Dispose()
    {
        ctx.Dispose();
    }
}

Таким образом, вызов вашего родительского класса в операторе using удалит ваш контекст при выходе из него.

person Benjamin Soulier    schedule 16.09.2016