L'unità del principio di lavoro sta causando un problema nell'applicazione MVC3

4

Sto implementando un sito Web utilizzando MVC3, Entity Framework 4.1 e Pattern Repositoty, Principio dell'unità di lavoro. Ma sto affrontando un grosso problema durante l'implementazione di questo.

Ho sviluppato una classe ObjectContext statica. Questa classe viene utilizzata in tutti i repository in modo da seguire il modello dell'unità di lavoro. Ho per esempio Cliente, repository IProduct. Io uso specificamente un solo repository in un controller e anche questo viene iniettato usando NInject.

CustomerController(ICustomer customer)
{
}

ProductController(IProduct product)
{
}

Poiché la classe di contesto dell'oggetto è statica e IProduct, ICustomer ha un costruttore con parametri che accetta la classe objectContext, questi due condivideranno la stessa istanza di ObjectContext.

Quando l'esecuzione è a thread singolo, tutto va bene, ma nel multithreading ottengo un'eccezione non gestita, perché un repository chiude la connessione che veniva utilizzata da altri. Penso che se creo la classe ObjectContext non statica, questo risolverà il problema (non ancora testato), ma l'unità di lavoro non verrà osservata.

Puoi suggerire una soluzione per questo?

    
posta Pravin Patil 02.02.2012 - 13:05
fonte

3 risposte

6

static ObjectContext class

In realtà è persino peggio di quello che pensi. La classe ObjectContext non è thread-safe, quindi anche se riesci a ottenere quella che ritieni sia una buona sincronizzazione, (senza bloccarla effettivamente) continuerai a generare eccezioni in un ambiente multi-utente.

Il team di ADO.NET consiglia di utilizzare un nuovo ObjectContext ogni volta che si pianifica di eseguire query sul database. In quale altro modo qualcuno potrebbe separare le proprie classi di accesso ai dati gli uni dagli altri, se così non fosse?

I think if I make ObjectContext class not-static then this will solve the problem(Not tested yet) but then Unit of Work will not be observed.

Non è vero affatto. L'unità di modello di lavoro non ha nulla a che fare con l'avere un singolo repository per un'intera applicazione - altrimenti, ogni esercitazione di framework di entità ti farebbe iniziare mostrandoti come creare il tuo ObjectContext statico.

Significa semplicemente che se non è possibile impegnare l'unità di lavoro, l'intero commit verrà annullato e l'intero commit deve avere successo perché abbia successo; è una singola transazione logica.

Se hai bisogno di mantenere gli oggetti in giro per la vita dell'applicazione, cerca nella cache in una struttura dati diversa da un ObjectContext.

    
risposta data 02.02.2012 - 14:54
fonte
3

Quello che vuoi è istanziare un ObjectContext per richiesta web, indipendentemente dal numero di accessi al database che potrebbero essere richiesti da quella richiesta. E tu non vuoi condividerlo con altre richieste web, altrimenti otterrai i tuoi problemi di multithreading.

L'approccio che prendo si basa su questo post del blog: " LINQ-to-SQL: la storia a più livelli " di Steve Sanderson. Sì, si tratta di LINQ-to-SQL, non di Entity Framework, ma è possibile adottare lo stesso approccio. Quando parla di DataContex LINQ-to-SQL, pensa EF ObjectContexts.

L'approccio che stai attualmente prendendo è quello che descrive come "Seconda storia: DataContext per applicazione", e hai scoperto i problemi di cui parla, vale a dire con la sicurezza dei thread. Vuoi muoverti verso ciò che chiama "Storia tre: DataContext per unità di lavoro (vale a dire per richiesta)", che implica la creazione di un ObjectContext per richiesta web e la memorizzazione in HttpContext.Current.Items , la cui durata è quella di un web richiesta ed è privato per quella richiesta.

Dato che stai già utilizzando un'iniezione di dipendenza, ti consigliamo di leggere l'ultima sezione "Stop! Non è ancora abbastanza buono" dove spiega come interrompere la dipendenza su HttpContext.Current usando una semplice inversione di controllo.

    
risposta data 03.02.2012 - 04:47
fonte
0

Usa il conteggio dei riferimenti sulla connessione (e su qualsiasi altro stato condiviso che richiede una pulizia speciale dopo l'uso).

Ogni volta che un oggetto inizia ad usare la connessione, incrementa il conteggio dei riferimenti. Quando l'oggetto è finito, decrementa il conteggio. Quando il conteggio raggiunge lo zero, chiudi la connessione.

Si vorrà utilizzare un blocco per proteggere il conteggio dei riferimenti e la logica di apertura / chiusura della connessione. Ci sono alcune condizioni di gara intorno alla connessione aperta / chiusa che potrebbero causare problemi, altrimenti.

Più in generale, dovrai preoccuparti della sincronizzazione su qualsiasi stato condiviso tra più thread. Se mantieni questo design, devi abituarti a controllare se le classi / funzioni sono prive di thread e aggiungere blocchi per proteggere tutto ciò che non è o di cui non sei sicuro. Se si dispone di più primitive di sincronizzazione, è necessario iniziare a preoccuparsi per l'ordine di acquisizione e la possibilità di deadlock.

Questo è uno degli enormi inconvenienti di qualsiasi cosa sia statica o condivisa in un'altra applicazione multithread. La sincronizzazione è davvero facile da rovinare e porta a bug difficili da riprodurre e diagnosticare. Assicurati di considerare questo nella tua valutazione del tuo design rispetto ad altri progetti che non richiedono uno stato condiviso.

    
risposta data 02.02.2012 - 13:34
fonte