sql >> Databasteknik >  >> RDS >> Sqlserver

.NET Entity Framework och transaktioner

Skapa ett globalt Entity Framework DbContext i en webbapplikation är mycket dålig. DbContext klass är inte trådsäker (och samma gäller för Entity Framework v1:s ObjectContext klass). Den är uppbyggd kring konceptet arbetsenhet och det betyder att du använder den för att driva ett enda användningsfall:alltså för en affärstransaktion. Det är tänkt att hantera en enda begäran.

Undantaget du får beror på att du för varje begäran skapar en ny transaktion, men försöker använda samma DbContext . Du har tur att DbContext upptäcker detta och gör ett undantag, för nu fick du reda på att det här inte kommer att fungera.

DbContext innehåller en lokal cache med enheter i din databas. Det låter dig göra en massa ändringar och slutligen skicka in dessa ändringar till databasen. När du använder en enda statisk DbContext , med flera användare som anropar SaveChanges på det objektet, hur ska man veta exakt vad som bör begås och vad som inte bör?

Eftersom den inte vet kommer den att spara alla ändringar, men vid den tidpunkten kan en annan begäran fortfarande göra ändringar. När du har tur kommer antingen EF eller din databas att misslyckas, eftersom enheterna är i ett ogiltigt tillstånd. Om du har otur sparas enheter som är i ett ogiltigt tillstånd framgångsrikt i databasen och du kan få reda på några veckor senare att din data har skadats.

Lösningen på ditt problem är att skapa minst en DbContext per begäran . Även om du i teorin skulle kunna cachelagra en objektkontext i användarsessionen, är detta också en dålig idé, eftersom i så fall DbContext kommer vanligtvis att leva för länge och kommer att innehålla inaktuella data (eftersom dess interna cache inte automatiskt uppdateras).

Observera också att ha en DbContext per tråd är ungefär lika dåligt som att ha en enda instans för hela webbapplikationen. ASP.NET använder en trådpool vilket innebär att en begränsad mängd trådar kommer att skapas under en webbapplikations livstid. Detta betyder i princip att de DbContext instanser kommer i så fall fortfarande att leva under applikationens livstid, vilket orsakar samma problem med inaktuella data.

Du kanske tror att ha en DbContext per tråd är faktiskt trådsäker, men så är vanligtvis inte fallet, eftersom ASP.NET har en asynkron modell som tillåter efterbehandling av förfrågningar på en annan tråd än där den startades (och de senaste versionerna av MVC och Web API tillåter till och med en godtyckligt antal trådar hanterar en enda begäran i sekventiell ordning). Det betyder att tråden som startade en begäran och skapade ObjectContext kan bli tillgänglig för att behandla en annan begäran långt innan den första begäran avslutades. Objekten som används i den begäran (som en webbsida, kontrollant eller någon affärsklass) kan dock fortfarande referera till den DbContext . Eftersom den nya webbförfrågan körs i samma tråd kommer den att få samma DbContext instans som vad den gamla begäran använder. Detta orsakar återigen tävlingsförhållanden i din applikation och orsakar samma trådsäkerhetsproblem som en global DbContext instans orsakar.



  1. Hur använder jag LINQ korrekt med MySQL?

  2. Kaskad kvarstår skapar dubbletter av rader?

  3. Varje värde visas i en ny rad HTML-tabell

  4. Hur man använder FILEPROPERTY() i SQL Server