Вопросы об объекте Entity Framework Context Lifetime

У меня есть некоторые вопросы о желаемом сроке жизни контекста Entity Framework в приложении ASP.NET MVC. Не лучше ли поддерживать контекст в кратчайшие сроки?

Рассмотрим следующее действие controllerа:

public ActionResult Index() { IEnumerable model; using (var context = new MyEntities()) { model = context.MyTable; } return View(model); } 

Приведенный выше код не будет работать, потому что контекст Entity Framework вышел из области видимости, в то время как представление отображает страницу. Как другие структурируют код выше?

Давайте спорить!

Я не согласен с общим мнением MVC + EF о том, что сохранение контекста в течение всего запроса является хорошей вещью по ряду причин:

Низкое увеличение производительности Знаете ли вы, как дорогое создание нового контекста базы данных? Ну … « DataContext легкий и не дорогой для создания », это от MSDN

Получите IoC неправильно, и все будет хорошо .. пока вы не перейдете в живую. Если вы настроили свой контейнер IoC, чтобы избавиться от своего контекста, и вы ошибаетесь, вы действительно действительно ошибаетесь. Я уже дважды видел массивные утечки памяти, созданные из контейнера IoC, не всегда правильно используя контекст. Вы не поймете, что настроили неправильно, пока ваши серверы не начнут рушиться во время обычных уровней одновременных пользователей. Это не произойдет в разработке, так что сделайте некоторые нагрузочные тесты!

Случайная ленивая загрузка. Вы возвращаете IQueryable из своих последних статей, чтобы вы могли перечислить их на своей домашней странице. Однажды кого-то попросят указать количество комментариев рядом с соответствующей статьей. Поэтому они добавляют простой бит кода в представление, чтобы показать счетчик комментариев, например …

 @foreach(var article in Model.Articles) { 
@article.Title @article.Comments.Count() comments
}

Выглядит хорошо, прекрасно работает. Но на самом деле вы не включили комментарии в возвращаемые данные, так что теперь это приведет к новому вызову базы данных для каждой статьи в цикле. SELECT N + 1. 10 статей = 11 запросов к базе данных. Ладно, так код неправильный, но легко сделать так, чтобы это произошло.

Это можно предотвратить, отключив свой контекст в вашем слое данных. Но не будет ли разрыв кода с исключением NullReferenceException в статье. Comments.Count ()? Да, это заставит вас отредактировать слой данных, чтобы получить данные, необходимые для слоя «Вид». Вот как это должно быть.

Чувствительность кода Существует только что-то не так, как попасть в базу данных из вашего представления. Вы знаете, что IQueryable на самом деле не попал в базу данных, но забыл об этом объекте. Убедитесь, что ваша firebase database удалена, прежде чем она покинет ваш уровень данных.

Итак, ответ

Ваш код должен быть (на мой взгляд) таким, как это

DataLayer:

 public List
GetArticles() { List
model; using (var context = new MyEntities()) { //for an example I've assumed your "MyTable" is a table of news articles model = (from mt in context.Articles select mt).ToList(); //data in a List so the database has been hit now and data is final } return model; }

controller:

 public ActionResult Index() { var model = new HomeViewModel(); //class with the bits needed for you view model.Articles = _dataservice.GetArticles(); //irrelevant how _dataService was intialised return View(model); } 

Как только вы это сделаете и поймете это, вы, возможно, начнете экспериментировать с контекстом дескриптора контейнера IoC, но определенно не раньше. Назовите мое предупреждение – я видел два больших сбоя:

Но честно делайте то, что вам нравится, программирование – это весело и должно быть вопросом предпочтения. Я просто говорю тебе свое. Но что бы вы ни делали, не начинайте использовать контекст IoC для каждого controllerа или для запроса только потому, что «все classные дети делают это». Сделайте это, потому что вы действительно действительно заботитесь о своих преимуществах и понимаете, как это делается правильно.

Я согласен с одним контекстом для запроса, мы обычно делаем это, связывая контекст .InRequestScope с использованием Ninject, который работает очень хорошо:

 Bind().ToSelf().InRequestScope(); 

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

 public ActionResult Index() { IEnumerable model; using (var context = new MyEntities()) { model = (from mt in context.MyTable select mt).ToArray(); } return View(model); } 

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

Во-первых, вам следует рассмотреть возможность доступа к базе данных для отдельных classов.

Во-вторых, моим любимым решением для этого является использование «одного контекста для запроса» (если вы используете MVC, я считаю, что это один контекст для каждого controllerа).

Запрошенное редактирование:

Посмотрите на этот ответ, возможно, это тоже поможет вам. Обратите внимание, что я использую webforms, поэтому не могу проверить его в MVC на данный момент, но это может быть полезно для вас или, по крайней мере, дать вам несколько указателей. https://stackoverflow.com/a/10153406/1289283

Пример использования этого dbcontext:

 public class SomeDataAccessClass { public static IQueryable GetAllProducts() { var products = from o in ContextPerRequest.Current.Products select o; return products; } } 

Тогда вы можете сделать что-то вроде этого:

 public ActionResult Index() { var products = SomeDataAccessClass.GetProducts(); return View(products); } 

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

Некоторым людям нравится еще немного подправить вещи, добавив шаблон UnitOfWork или, возможно, контейнеры IoC … Но мне нравится этот подход больше из-за его простоты.

Можете ли вы использовать метод расширения LINQ .ToList() как таковой:

 public ActionResult Index() { IEnumerable model; using (var context = new MyEntities()) { model = (from mt in context.MyTable select mt).ToList(); } return View(model); } 
Interesting Posts

Неправильно ли использовать перерыв в цикле for?

Кто-нибудь знает пример низкого уровня (без фреймворка) списка перетаскивания и переустановки?

Что подразумевается под «streamобезопасным» кодом?

Внутренний разъем S / PDIF на материнской плате Gigabyte Z97

Выполнение скрипта PowerShell через контекстное меню проводника по элементам, содержащим амперсанды в их именах

Windows не может установить требуемые файлы. Файл может быть поврежден или отсутствует. (0x80070570)

Всегда ли инициализируются ints?

Функция String.indexOf в C

Отключите активацию панели меню, когда Alt нажата в Windows 7

Решение проблем зависимостей в Apache Spark

Почему GetType возвращает System.Int32 вместо Nullable ?

Как вставить окно Google Chrome в родительское окно?

Netbeans, как установить аргументы командной строки в Java

Обычная аутентификация для REST API с использованием Spring restTemplate

Массивы против векторов: вводные сходства и различия

Давайте будем гением компьютера.