Мы используем структуру сущностей для связи с базой данных в наших методах службы WCF, недавно мы запускаем инструмент проверки кода в нашем сервисном коде. Как обычно, у нас было много предложений по обзору с помощью инструмента, и многие комментарии к обзору предлагали избавиться от объекта контекста Entity Framework. Итак, мой вопрос заключается в том, что я использую объект контекста Entity Framework внутри метода, и как только я выхожу из метода, GC не очищает объект контекста? нам нужно явно удалять объект контекста?
Требуется контекстный объект для размещения объекта Entity Framework
Ответ 1
Просто: DbContext
реализует IDisposable
, поэтому вы должны избавиться от него вручную, как только вы закончите с ним.
Вам не нужно избавляться от него, потому что GC в конечном итоге соберет его, но GC не детерминирован: вы никогда не знаете, когда будет "в конце концов". Пока он не будет размещен, он будет удерживать ресурсы, которые не используются - например, он может все еще иметь открытое соединение с базой данных. Эти ресурсы не освобождаются до тех пор, пока GC не будет запущен, если вы не будете утилизировать вручную. В зависимости от конкретных деталей вы можете обнаружить, что у вас есть излишне заблокированные сетевые ресурсы, доступ к файлам, и вы наверняка сохраните больше памяти, чем вам нужно.
Есть и еще один потенциальный риск: когда вы распоряжаетесь объектом вручную, GC обычно не нужно вызывать Finalizer на этом объекте (если таковой имеется). Если вы оставите GC для автоматического удаления объекта с помощью Finalizer, он поместит объект в очередь Finalizer и автоматически продвинет объект к следующему поколению GC. Это означает, что объект с финализатором всегда будет зависать на порядки дольше, чем нужно, прежде чем он будет GCed (поскольку последовательные поколения GC собираются реже). DbContext
, вероятно, попадет в эту категорию, поскольку базовое соединение с базой данных будет неуправляемым кодом.
(Полезно ссылка.)
Ответ 2
Я думаю, что лучший подход заключается в его кодировании в операторе using
using(var cx = new DbContext())
{
//your stuff here
}
поэтому он получил автоматическое расположение
Ответ 3
В общем, если что-то реализует IDisposable
, это хорошая идея (TM), чтобы явным образом распоряжаться ею, когда вы закончите. Это особенно верно, если вы не владеете реализацией указанного объекта; вы должны рассматривать это как черный ящик в этом случае. Кроме того, даже если это не обязательно "нужно", чтобы избавиться от него сейчас, оно может быть в будущем.
Поэтому IMHO вопрос о том, нужно ли вам "явно" распоряжаться объектом, не имеет значения. Если он просит избавиться - в силу реализации IDisposable
- его следует утилизировать.
Ответ 4
Рекомендуемая вещь, связанная с DBContext, заключается в том, чтобы вообще не использовать ее (это правило является исключением из правила в большинстве случаев), хотя это одноразовый объект.
Пример проблемы. Первый пример - это вызов и оценка его в операторе using, а второй - после него. (первые запускаются, вторая вызывает ошибку The operation cannot be completed because the DbContext has been disposed.
)
List<Test> listT;
using (Model1 db = new Model1())
{
listT = db.Tests.ToList(); //ToList Evaluates
}
foreach (var a in listT)
{
Console.WriteLine(a.value);
}
IEnumerable<Test> listT1;
using (Model1 db = new Model1())
{
listT1 = db.Tests;
}
foreach (var a in listT1) //foreach evaluates (but at wrong time)
{
Console.WriteLine(a.value);
}
То же самое происходит в
IEnumerable<Test> listT1;
Model1 db = new Model1();
listT1 = db.Tests;
db.Dispose();
foreach (var a in listT1) //foreach evaluates (but at wrong time)
{
Console.WriteLine(a.value);
}
В то время как вы не открываете соединение вручную, вы можете безопасно использовать
IEnumerable<Test> listT1;
Model1 db = new Model1();
listT1 = db.Tests;
foreach (var a in listT1) //foreach evaluates (but at wrong time)
{
Console.WriteLine(a.value);
}
и никогда не удаляйте. поскольку он будет заботиться о себе при большинстве обстоятельств, как это он и сделал.
Теперь вы должны открыть соединение силой, тогда контекст не будет автоматически закрывать его, когда передача будет выполнена, поскольку она не знает, когда и затем вы должны/должны располагать объект или закрывать соединение и держать объект нераскрытым.
Дополнительная полуночи:
Ответ 5
Нет необходимости явно удалять DbContext.
Это старое удержание инструментов pre-DbContext. DbContext - это управляемый код, который самостоятельно поддерживает соединения с базой данных. Почему кувалда это? Что за спешка? Почему бы просто не позволить сборщику мусора выбрать наилучшее время для очистки, когда машина простаивает или нуждается в памяти? Также обратитесь к этому сообщению: https://blog.jongallant.com/2012/10/do-i-have-to-call-dispose-on-dbcontext/
Не заботясь о том, чтобы избавиться от него, вы упростите и оптимизируете свой код. Обычно я могу наследовать от класса "помощника" базы данных, где я использую метод получения, чтобы либо вернуть уже существующий экземпляр DbContext, либо создать новый экземпляр. ,
public class DataTools
{
private AppContext _context;
protected AppContext Context => _context ?? (_context = new AppContext());
}
pubic class YourApp : DataTools
{
public void DoLotsOfThings()
{
var = Context.SomeTable.Where(s => s.....);
var stuff = GetSomeThing();
foreach(){}
}
Public string GetSomething()
{
return Context.AnotherTable.First(s => s....).Value;
}
}