Oprettelse af én global enhedsramme DbContext
i en webapplikation er meget dårlig. DbContext
klasse er ikke trådsikker (og det samme gælder for Entity Framework v1's ObjectContext
klasse). Det er bygget op omkring konceptet arbejdsenheden
og det betyder, at du bruger det til at drive en enkelt brugssag:altså til en forretningstransaktion. Det er beregnet til at håndtere en enkelt anmodning.
Undtagelsen, du får, sker, fordi du for hver anmodning opretter en ny transaktion, men prøv at bruge den samme DbContext
. Du er heldig, at DbContext
opdager dette og kaster en undtagelse, for nu har du fundet ud af, at dette ikke vil virke.
DbContext
indeholder en lokal cache af enheder i din database. Det giver dig mulighed for at foretage en masse ændringer og til sidst indsende disse ændringer til databasen. Når du bruger en enkelt statisk DbContext
, med flere brugere, der kalder SaveChanges
på det objekt, hvordan skal det vide, hvad der præcist skal begås, og hvad der ikke bør?
Fordi den ikke ved det, gemmer den alt ændringer, men på det tidspunkt kan en anden anmodning stadig foretage ændringer. Når du er heldig, vil enten EF eller din database fejle, fordi entiteterne er i en ugyldig tilstand. Hvis du er uheldig, bliver enheder, der er i en ugyldig tilstand, gemt i databasen, og du finder muligvis ud af uger senere, at dine data er blevet beskadiget.
Løsningen på dit problem er at oprette mindst én DbContext
pr. anmodning
. Selvom du i teorien kunne cache en objektkontekst i brugersessionen, er dette også en dårlig idé, for i så fald er DbContext
vil typisk leve for længe og vil indeholde forældede data (fordi dens interne cache ikke automatisk bliver opdateret).
Bemærk også, at have én DbContext
per tråd er omtrent lige så slemt som at have én enkelt instans til den komplette webapplikation. ASP.NET bruger en trådpulje, hvilket betyder, at en begrænset mængde tråde vil blive oprettet i løbet af en webapplikations levetid. Dette betyder grundlæggende, at disse DbContext
instanser vil i så fald stadig leve i hele applikationens levetid, hvilket forårsager de samme problemer med forældede data.
Du tror måske, at have én DbContext
pr. tråd er faktisk trådsikker, men dette er normalt ikke tilfældet, da ASP.NET har en asynkron model, der tillader efterbehandlingsanmodninger på en anden tråd, end hvor den blev startet (og de nyeste versioner af MVC og Web API tillader endda en vilkårligt antal tråde håndterer en enkelt anmodning i sekventiel rækkefølge). Det betyder, at den tråd, der startede en anmodning og skabte ObjectContext
kan blive tilgængelig til at behandle en anden anmodning længe før den oprindelige anmodning blev afsluttet. De objekter, der blev brugt i denne anmodning (såsom en webside, controller eller enhver virksomhedsklasse), kan dog stadig referere til den DbContext
. Da den nye webanmodning kører i den samme tråd, vil den få den samme DbContext
instans som det, den gamle anmodning bruger. Dette forårsager igen løbsforhold i din applikation og forårsager de samme trådsikkerhedsproblemer som en global DbContext
instans forårsager.