Tworzenie jednego globalnego Entity Framework DbContext
w aplikacji internetowej jest bardzo zła. DbContext
Klasa nie jest bezpieczna wątkowo (i te same blokady dla ObjectContext
Entity Framework v1 klasa). Jest zbudowany wokół koncepcji jednostki pracy
a to oznacza, że używasz go do obsługi pojedynczego przypadku użycia:a więc dla transakcji biznesowej. Ma za zadanie obsłużyć jedno żądanie.
Pojawia się wyjątek, ponieważ dla każdego żądania tworzysz nową transakcję, ale spróbuj użyć tego samego DbContext
. Masz szczęście, że DbContext
wykrywa to i zgłasza wyjątek, ponieważ teraz dowiedziałeś się, że to nie zadziała.
DbContext
zawiera lokalną pamięć podręczną encji w Twojej bazie danych. Pozwala na wprowadzenie wielu zmian i wreszcie przesłanie tych zmian do bazy danych. Podczas korzystania z pojedynczego statycznego DbContext
, z wieloma użytkownikami dzwoniącymi do SaveChanges
na tym obiekcie, skąd ma wiedzieć, co dokładnie powinno zostać popełnione, a czego nie?
Ponieważ nie wie, uratuje wszystko zmiany, ale w tym momencie inne żądanie może nadal wprowadzać zmiany. Jeśli masz szczęście, albo EF, albo baza danych nie powiedzie się, ponieważ jednostki są w nieprawidłowym stanie. Jeśli masz pecha, podmioty, które są w nieprawidłowym stanie, są pomyślnie zapisywane w bazie danych i możesz dowiedzieć się kilka tygodni później, że Twoje dane zostały uszkodzone.
Rozwiązaniem Twojego problemu jest utworzenie co najmniej jednego DbContext
zazwyczaj będzie żył zbyt długo i będzie zawierał nieaktualne dane (ponieważ jego wewnętrzna pamięć podręczna nie zostanie automatycznie odświeżona).
Pamiętaj również, że posiadanie jednego DbContext
na wątek jest tak samo złe, jak posiadanie jednej instancji dla kompletnej aplikacji internetowej. ASP.NET korzysta z puli wątków, co oznacza, że w okresie istnienia aplikacji internetowej zostanie utworzona ograniczona liczba wątków. Zasadniczo oznacza to, że te DbContext
w takim przypadku instancje będą nadal działać przez cały czas życia aplikacji, powodując te same problemy z nieaktualnością danych.
Możesz pomyśleć, że posiadanie jednego DbContext
na wątek jest w rzeczywistości bezpieczny wątkowo, ale zwykle tak nie jest, ponieważ ASP.NET ma model asynchroniczny, który umożliwia kończenie żądań w innym wątku niż ten, w którym został uruchomiony (a najnowsze wersje MVC i Web API umożliwiają nawet dowolna liczba wątków obsługuje jedno żądanie w kolejności). Oznacza to, że wątek, który rozpoczął żądanie i utworzył ObjectContext
może stać się dostępny do przetworzenia innego żądania na długo przed zakończeniem tego żądania. Jednak obiekty użyte w tym żądaniu (takie jak strona internetowa, kontroler lub dowolna klasa biznesowa) mogą nadal odwoływać się do tego DbContext
. Ponieważ nowe żądanie sieciowe działa w tym samym wątku, otrzyma ten sam DbContext
wystąpienie jako to, czego używa stare żądanie. To ponownie powoduje wyścig w Twojej aplikacji i powoduje te same problemy z bezpieczeństwem wątków, co jeden globalny DbContext
przyczyny wystąpienia.