Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

.NET Entity Framework e transazioni

Creazione di un Entity Framework globale DbContext in un'applicazione web è pessimo. Il DbContext la classe non è thread-safe (e lo stesso vale per ObjectContext di Entity Framework v1 classe). È costruito attorno al concetto di unità di lavoro e questo significa che lo utilizzi per operare un singolo caso d'uso:quindi per una transazione commerciale. Ha lo scopo di gestire una singola richiesta.

L'eccezione che ottieni si verifica perché per ogni richiesta crei una nuova transazione, ma prova a utilizzare lo stesso DbContext . Sei fortunato che il DbContext lo rileva e genera un'eccezione, perché ora hai scoperto che non funzionerà.

Il DbContext contiene una cache locale di entità nel database. Ti consente di apportare un sacco di modifiche e infine di inviare tali modifiche al database. Quando si utilizza un singolo DbContext statico , con più utenti che chiamano SaveChanges su quell'oggetto, come dovrebbe sapere cosa esattamente dovrebbe essere commesso e cosa no?

Poiché non lo sa, salverà tutto modifiche, ma a quel punto un'altra richiesta potrebbe ancora apportare modifiche. Quando sei fortunato, EF o il tuo database falliranno, perché le entità sono in uno stato non valido. Se sei sfortunato, le entità che si trovano in uno stato non valido vengono salvate correttamente nel database e potresti scoprire settimane dopo che i tuoi dati sono stati danneggiati.

La soluzione al tuo problema è creare almeno un DbContext per richiesta . Mentre in teoria potresti memorizzare nella cache un contesto di oggetti nella sessione utente, anche questa è una cattiva idea, perché in quel caso il DbContext in genere vivrà troppo a lungo e conterrà dati non aggiornati (perché la sua cache interna non verrà aggiornata automaticamente).

Nota anche che avere un DbContext per thread è grave quanto avere una singola istanza per l'applicazione Web completa. ASP.NET utilizza un pool di thread, il che significa che verrà creata una quantità limitata di thread durante la durata di un'applicazione Web. Ciò significa sostanzialmente che quei DbContext in tal caso le istanze continueranno a vivere per tutta la vita dell'applicazione, causando gli stessi problemi di obsolescenza dei dati.

Potresti pensare che avere un DbContext per thread è in realtà thread-safe, ma di solito non è così, poiché ASP.NET ha un modello asincrono che consente di completare le richieste su un thread diverso da quello in cui è stato avviato (e le ultime versioni di MVC e API Web consentono anche un un numero arbitrario di thread gestisce una singola richiesta in ordine sequenziale). Ciò significa che il thread che ha avviato una richiesta e creato ObjectContext può diventare disponibile per elaborare un'altra richiesta molto prima che quella richiesta iniziale sia terminata. Tuttavia, gli oggetti utilizzati in quella richiesta (come una pagina Web, un controller o qualsiasi classe aziendale), potrebbero comunque fare riferimento a quel DbContext . Poiché la nuova richiesta Web viene eseguita nello stesso thread, otterrà lo stesso DbContext esempio come quello che sta usando la vecchia richiesta. Ciò causa nuovamente condizioni di competizione nella tua applicazione e causa gli stessi problemi di sicurezza dei thread di un DbContext globale cause dell'istanza.