Създаване на една глобална Entity Framework DbContext
в уеб приложение е много лошо. DbContext
класът не е безопасен за нишки (и същото важи за ObjectContext
на Entity Framework v1 клас). Той е изграден около концепцията за работна единица
и това означава, че го използвате, за да работите с един случай на употреба:следователно за бизнес транзакция. Той е предназначен да обработва една единствена заявка.
Изключението, което получавате, се случва, защото за всяка заявка създавате нова транзакция, но опитайте да използвате същия DbContext
. Имате късмет, че DbContext
открива това и хвърля изключение, защото сега разбрахте, че това няма да работи.
DbContext
съдържа локален кеш на обекти във вашата база данни. Тя ви позволява да направите куп промени и накрая да изпратите тези промени в базата данни. Когато използвате единичен статичен DbContext
, като множество потребители извикват SaveChanges
на този обект, как трябва да се знае какво точно трябва да бъде ангажирано и какво не?
Тъй като не знае, ще запази всички промени, но в този момент друга заявка може все още да прави промени. Когато имате късмет, EF или вашата база данни ще се провалят, защото обектите са в невалидно състояние. Ако нямате късмет, обектите, които са в невалидно състояние, се записват успешно в базата данни и може да разберете седмици по-късно, че данните ви са повредени.
Решението на вашия проблем е да създадете поне един DbContext
на заявка
. Въпреки че на теория можете да кеширате контекст на обект в потребителската сесия, това също е лоша идея, защото в този случай DbContext
обикновено ще живее твърде дълго и ще съдържа остарели данни (тъй като неговият вътрешен кеш няма да се опреснява автоматично).
Също така имайте предвид, че наличието на един DbContext
на нишка е почти толкова лошо, колкото да имате един единствен екземпляр за цялото уеб приложение. ASP.NET използва набор от нишки, което означава, че ограничен брой нишки ще бъдат създадени по време на живота на уеб приложението. Това основно означава, че тези DbContext
екземплярите в този случай ще продължат да съществуват през целия живот на приложението, причинявайки същите проблеми с остарелостта на данните.
Може би си мислите, че наличието на един DbContext
на нишка всъщност е безопасна за нишка, но това обикновено не е така, тъй като ASP.NET има асинхронен модел, който позволява завършване на заявки в нишка, различна от тази, от която е стартирана (и най-новите версии на MVC и Web API дори позволяват произволен брой нишки обработват една заявка в последователен ред). Това означава, че нишката, която е стартирала заявка и е създала ObjectContext
може да стане достъпен за обработка на друга заявка много преди тази първоначална заявка да приключи. Обектите, използвани в тази заявка обаче (като уеб страница, контролер или всякаква бизнес класа), все пак може да препращат към този DbContext
. Тъй като новата уеб заявка се изпълнява в същата нишка, тя ще получи същия DbContext
пример като това, което използва старата заявка. Това отново причинява условия на състезание във вашето приложение и причинява същите проблеми с безопасността на нишката като това, което има един глобален DbContext
причини за екземпляр.