Entity Framework e Connection Pooling

Recentemente ho iniziato a utilizzare Entity Framework 4.0 nella mia applicazione .NET 4.0 e sono curioso di alcune cose relative al pooling.

  1. Il pool di connessioni che conosco è gestito dal provider di dati ADO.NET, nel mio caso quello di MS SQL Server. Questo si applica quando installi un nuovo contesto di quadro ( ObjectContext ), cioè il new MyDatabaseModelEntities() parametri?

  2. Quali sono i vantaggi e gli svantaggi di a) creare un contesto di quadro globali per l’applicazione (ad esempio un’istanza statica) o b) creare ed esporre un contesto di entity framework per ogni operazione / metodo, con un blocco using .

  3. Eventuali altri consigli, migliori pratiche o approcci comuni per determinati scenari che dovrei conoscere?

  1. Il pool di connessioni viene gestito come in qualsiasi altra applicazione ADO.NET. La connessione di quadro utilizza ancora la connessione di database tradizionale con la stringa di connessione tradizionale. Credo che tu possa distriggersre il pool di connessioni nella stringa di connessione se non vuoi usarlo. (Ulteriori informazioni su SQL Server Connection Pooling (ADO.NET) )
  2. Mai e poi mai usare il contesto globale. ObjectContext implementa internamente diversi pattern, tra cui Identity Map e Unit of Work. L’impatto dell’utilizzo del contesto globale è diverso per tipo di applicazione.
  3. Per le applicazioni Web, utilizzare un singolo contesto per richiesta. Per i servizi Web, utilizzare un singolo contesto per chiamata. Nelle applicazioni WinForms o WPF utilizzare un singolo contesto per modulo o per presentatore. Ci possono essere alcuni requisiti speciali che non consentono di utilizzare questo approccio, ma nella maggior parte delle situazioni questo è sufficiente.

Se vuoi sapere quale impatto ha il contesto object singolo per l’applicazione WPF / WinForm, controlla questo articolo . Si tratta di NHibernate Session ma l’idea è la stessa.

Modificare:

Quando si utilizza EF, per impostazione predefinita carica ogni quadro solo una volta per contesto. La prima query crea un’istanza di entity framework e la memorizza internamente. Qualsiasi query successiva che richiede un’entity framework con la stessa chiave restituisce questa istanza memorizzata. Se i valori nell’archivio dati sono modificati, si riceve comunque l’ quadro con i valori della query iniziale. Questo è chiamato Pattern Mappa di id quadro . È ansible forzare il contesto dell’object per ricaricare l’ quadro, ma ricaricherà una singola istanza condivisa.

Qualsiasi modifica apportata all’ quadro non viene mantenuta finché non si chiama SaveChanges sul contesto. È ansible apportare modifiche a più quadro e memorizzarle contemporaneamente. Questo è chiamato modello Unità di lavoro . Non puoi dire selettivamente quale quadro allegata modificata vuoi salvare.

Combina questi due modelli e vedrai alcuni effetti interessanti. Hai solo un’istanza di quadro per l’intera applicazione. Qualsiasi modifica all’entity framework influisce sull’intera applicazione anche se le modifiche non sono ancora persistenti (commesse). Nella maggior parte delle volte questo non è quello che vuoi. Supponiamo di avere un modulo di modifica nell’applicazione WPF. Stai lavorando con l’entity framework e decidi di annullare l’editazione complessa (cambiando valori, aggiungendo quadro correlate, rimuovendo altre quadro correlate, ecc.). Ma l’entity framework è già stata modificata in un contesto condiviso. Cosa farai? Suggerimento: non conosco alcun CancelChanges o UndoChanges su ObjectContext .

Penso che non dobbiamo discutere lo scenario del server. La semplice condivisione di una singola entity framework tra più richieste HTTP o chiamate di servizi Web rende l’applicazione inutile. Qualsiasi richiesta può semplicemente triggersre SaveChanges e salvare dati parziali da un’altra richiesta perché si sta condividendo una singola unità di lavoro tra tutti loro. Ciò avrà anche un altro problema: il contesto e qualsiasi manipolazione con quadro nel contesto o una connessione al database utilizzata dal contesto non è thread-safe.

Anche per un’applicazione di sola lettura, un contesto globale non è una buona scelta perché probabilmente desideri dati nuovi ogni volta che esegui una query sull’applicazione.

Secondo Daniel Simmons:

Creare una nuova istanza di ObjectContext in un’istruzione Using per ogni metodo di servizio in modo che venga eliminata prima del ritorno del metodo. Questo passaggio è fondamentale per la scalabilità del tuo servizio. Garantisce che le connessioni al database non vengano mantenute aperte per tutte le chiamate di servizio e che lo stato temporaneo utilizzato da una particolare operazione venga sottoposto a garbage collection al termine di tale operazione. Entity Framework memorizza automaticamente nella cache i metadati e le altre informazioni di cui ha bisogno nel dominio dell’app e ADO.NET raggruppa le connessioni al database, quindi ricreare il contesto ogni volta è un’operazione rapida.

Questo è dal suo articolo completo qui:

http://msdn.microsoft.com/en-us/magazine/ee335715.aspx

Credo che questo consiglio si estenda alle richieste HTTP, quindi sarebbe valido per ASP.NET. Un’applicazione client stateful, come un’applicazione WPF, potrebbe essere l’unico caso per un contesto “condiviso”.

Accorando alla documentazione EF6 (4,5 anche): https://msdn.microsoft.com/en-us/data/hh949853#9

9.3 Contesto per richiesta

I contesti di Entity Framework sono pensati per essere utilizzati come istanze di breve durata al fine di fornire l’esperienza di performance ottimale . Si prevede che i contesti siano di breve durata e scartati, e in quanto tali sono stati implementati per essere molto leggeri e per riutilizzare i metadati quando ansible. Negli scenari web è importante tenerlo a mente e non avere un contesto per più della durata di una singola richiesta. Analogamente, in scenari non Web, il contesto deve essere scartato in base alla comprensione dei diversi livelli di memorizzazione nella cache in Entity Framework. In generale, si dovrebbe evitare di avere un’istanza di contesto per tutta la durata dell’applicazione, nonché i contesti per thread e contesti statici.

Il codice sottostante ha aiutato il mio object ad essere aggiornato con nuovi valori di database. Il comando Entry (object) .Reload () forza l’object a richiamare i valori del database

 GM_MEMBERS member = DatabaseObjectContext.GM_MEMBERS.FirstOrDefault(p => p.Username == username && p.ApplicationName == this.ApplicationName); DatabaseObjectContext.Entry(member).Reload();