Возможно ли, чтобы класс Datacontext был статическим, используя Entity Framework - PullRequest
0 голосов
/ 31 октября 2019

В одном из моих классов мы унаследовали проект, которым пользуется школа, в которую я иду. Это проект ASP.NET Entity Framework, который использует несколько API для извлечения данных, а затем соединяется с локальной базой данных, чтобы предоставить нам все данные, которые нам нужны для работы. В настоящее время у меня есть Инструктор, пытающийся убедить нас в том, что создание статического класса DataContext - это самая разумная вещь на данный момент, чтобы не удалять контекст в конце вызова контроллера.

Насколько я понимаю, это очень сложно, если не невозможно, потому что процесс - это действие, вызванное действием> контекст создан> действие завершено> контекст удален. Действие - это любой вызов метода, и хотя мы не используем контекст, Entity Framework нуждается в этом. Я весь слух этого, потому что я не подвергся воздействию Entity Framework. Спасибо

Ответы [ 2 ]

5 голосов
/ 31 октября 2019

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

0 голосов
/ 01 ноября 2019

Просто чтобы добавить некоторый дополнительный контекст на случай, если кто-нибудь столкнется с этим вопросом (включая вашего инструктора :)

Преподаватель может связать единственное время «разогрева», необходимое для первого доступа к DbContext, кразрешить его сопоставления со стоимостью для всех экземпляров DbContext, но EF выполняет эту операцию один раз для процесса. (статический) Как только это произойдет, создание и уничтожение DbContexts будут дешевыми.

Я не могу думать ни о причине, ни о реальном сценарии, который я бы когда-либо рассматривал или рекомендовал статический или долгоживущий DbContext. Кто-то может поспорить, что DbContext с его кеш-запросом будет занимать больше ресурсов на веб-сервере, чем один общий экземпляр, но недолговечные экземпляры должны только кэшировать / отслеживать объекты, необходимые для обслуживания этого запроса, а затем утилизировать. (много маленьких против одного большого аргумента)

Одиночные DbContexts приносят значительные проблемы, особенно в ASP.Net. DbContexts не являются поточно-ориентированными, что приводит к проблемам отслеживания сущностей между потоками, и ASP.Net будет использовать потоки для ответа на запросы. Чем дольше контекст жив, тем больше становится его кеш. Некоторые могут возразить, что cache = fast, но чем больше становится ваш кеш, тем больше времени EF тратит на проверку ссылок на результаты поиска. Это связывает ваш сервер приложений, а не делит нагрузку с сервером базы данных для получения свежих данных по требованию. (это может быть асинхронным / ожидаемым сервером приложений для возврата к обработке запросов) EF не выполняет устаревшие проверки своего кэша, поэтому долгоживущие кэши обслуживают все большие объемы устаревших данных, которые могут быть обновлены другими способами. Это также может привести к непоследовательному поведению при доступе к связанным коллекциям сущностей. Для сущностей, которые загружены без загруженных коллекций, EF все равно будет проходить через все кэшированные сущности и связывать любые, о которых он знает. Это требует времени и может привести к возвращению неполных данных.

Например, если у нас был объектный граф, состоящий из:

Parent_1
  - Child_1
  - Child_2
  - Child_3

, то мы сделали что-то подобное из относительно свежего состояния данных:

var child = _staticContext.Children.Single(x => x.ChildId == 1);

затем позже сделал:

var parent = _staticContext.Parents.Single(x => x.ParentId == 1);

Пока ленивая загрузка включена (и коллекция Parent.Children является виртуальной), тогда это должно быть хорошо и parent.Children. Счет будет равен 3 после ленивого вызова нагрузки. Однако, если отложенная загрузка отключена или коллекция не является виртуальной, то в этом случае parent.Children.Count вернется с «1», а не с ожидаемым «0», где не было указано или ожидается отложенная или отложенная загрузка, а не«3», которая представляет реальные данные. Это может привести к разным результатам, появляющимся между запусками, или между отладкой и производством, и ошибками, если код настроен на загрузку с нетерпением (отложенная загрузка отключена), и кто-то забывает Include.

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

// Short-lived contexts for demonstration /w lazy loading implemented:
using (var context = new TestDbContext()) // represents our long-lived, static context...
{
    var child = context.Children.Single(x => x.ChildId == 2);
    Assert.AreEqual("Sean", child.Name);
    var parent = context.Parents.AsNoTracking().Single(x => x.ParentId == 1);
    using(var innerContext = new TestDbContext()) // a short-lived context somewhere in a call stack, or an external process modifying data...
    {
       var sean = innerContext.Children.Single(x => x.ChildId == 2);
       sean.Name = "Shawn";
       innerContext.SaveChanges();
    }

    Console.Writeline(child.Name);
    var parentsChild = parent.Children.Single(x => x.ChildId == 2); // Lazy load gets triggered here.
    Console.Writeline(parentsChild.Name); 
    Console.Writeline(child.Name);
}

Что вы ожидаете увидеть на выходе? «Шон» или «Шон»?

При отложенной загрузке в первой строке будет напечатано «Шон», а во второй - «Шон», хотя в долгоживущем контексте хранится кэшированная копия в памяти. ,Как насчет 3-й строки? Конечно, теперь, когда EF вызвал ленивую загрузку для дочернего элемента # 2, и у него есть отслеживаемый экземпляр для объекта с таким идентификатором, он будет обновлен? Нет. "Шон" еще. Теперь еще интереснее то, что child и parentsChild представляют одну и ту же дочернюю запись в базе данных (ID ребенка № 2) child говорит, что его зовут "Шон", а parentsChild говорит, что его зовут "Шон». Обычно EF не допускает множественных ссылок на одну и ту же сущность. Что произойдет, если мы добавим:

child.Name = "Fred";
context.SaveChanges();

Как насчет:

parentsChild.Name = "Ginger";
context.SaveChanges();

Как насчет:

child.Name = "Fred";
parentsChild.Name = "Ginger";
context.SaveChanges();

Что происходит в этих случаях, обновляется ли, EF создает исключение для нескольких отслеживаемых экземпляров? В статических контекстах отслеживаемые экземпляры можно изменять везде и в любом месте области приложения, а SaveChanges можно также вызывать где угодно и везде, вызывая сохранение всех измененных отслеживаемых экземпляров. Это может означать, что недопустимые / неполные изменения, предпринятые где-либо, могут загрязнить отслеживание изменений контекста, вызывая неожиданные сбои других вызовов SaveChanges в других областях без причины сбоя для отслеживания в точке сбоя.

В ASP. Нет, DbContext должен жить не дольше, чем запрос, и даже короче, например, для единицы работы для фиксации связанных изменений. (подумайте о транзакции) Даже в приложениях Windows DbContext должен жить только достаточно долго, чтобы обслуживать запрошенные данные или выполнять действия высокого уровня.

Статический / долгоживущий DbContexts? в двух словах, просто не делай этого. :)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...