2010-09-06 20 views
239

Recientemente comencé a usar Entity Framework 4.0 en mi aplicación .NET 4.0 y tengo curiosidad acerca de algunas cosas relacionadas con la agrupación.Entity Framework y Connection Pooling

  1. La agrupación de conexiones, como sé, está gestionada por el proveedor de datos ADO.NET, en mi caso, el del servidor MS SQL. ¿Esto se aplica cuando crea una instancia de un nuevo contexto de entidades (ObjectContext), es decir, el parámetro new MyDatabaseModelEntities()?

  2. Cuáles son las ventajas y desventajas de a) crear un contexto de entidades globales para la aplicación (es decir, una instancia estática) ob) crear y exponer un contexto de entidades para cada operación/método dado, con un bloque using.

  3. ¿Alguna otra recomendación, mejores prácticas o enfoques comunes para ciertos escenarios que debería conocer?

Respuesta

347
  1. La agrupación de conexiones se maneja como en cualquier otra aplicación ADO.NET. La conexión de entidad todavía usa la conexión de base de datos tradicional con la cadena de conexión tradicional. Creo que puede desactivar el agrupamiento de conexión en la cadena de conexión si no desea usarlo. (Leer más sobre SQL Server Connection Pooling (ADO.NET))
  2. Nunca uses el contexto global. ObjectContext implementa internamente varios patrones, incluidos Identity Map y Unit of Work. El impacto del uso del contexto global es diferente por tipo de aplicación.
  3. Para aplicaciones web, use un contexto único por solicitud. Para servicios web, use un contexto único por llamada. En WinForms o la aplicación WPF, use un contexto único por formulario o por presentador. Puede haber algunos requisitos especiales que no permitirán utilizar este enfoque, pero en la mayoría de las situaciones esto es suficiente.

Si desea saber qué impacto tiene el contexto de objeto único para la aplicación WPF/WinForm, consulte este article. Se trata de NHibernate Session, pero la idea es la misma.

Editar:

Cuando se utiliza EF que por defecto tiene cargada cada entidad sólo una vez por el contexto. La primera consulta crea instancia de entidad y la almacena internamente. Cualquier consulta posterior que requiera entidad con la misma clave devuelve esta instancia almacenada. Si los valores en el almacén de datos cambiaron, aún recibirá la entidad con los valores de la consulta inicial. Esto se llama Patrón de mapa de identidad. Puede forzar el contexto del objeto para volver a cargar la entidad, pero volverá a cargar una única instancia compartida.

Cualquier cambio realizado en la entidad no se conserva hasta que llame al SaveChanges en el contexto. Puede hacer cambios en múltiples entidades y almacenarlas a la vez.Esto se llama Unidad de trabajo patrón. No puede decir de forma selectiva qué entidad adjunta modificada desea guardar.

Combine estos dos patrones y verá algunos efectos interesantes. Solo tiene una instancia de entidad para toda la aplicación. Cualquier cambio en la entidad afecta a toda la aplicación, incluso si los cambios aún no se mantienen (comprometidos). En la mayoría de los casos, esto no es lo que quieres. Supongamos que tiene un formulario de edición en la aplicación WPF. Está trabajando con la entidad y decide cancelar la edición compleja (cambio de valores, adición de entidades relacionadas, eliminación de otras entidades relacionadas, etc.). Pero la entidad ya está modificada en el contexto compartido. ¿Qué harás? Sugerencia: no conozco ningún CancelChanges o UndoChanges en ObjectContext.

Creo que no tenemos que hablar sobre el escenario del servidor. Simplemente compartir una sola entidad entre múltiples solicitudes HTTP o llamadas al servicio web hace que su aplicación sea inútil. Cualquier solicitud solo puede activar SaveChanges y guardar datos parciales de otra solicitud porque está compartiendo una sola unidad de trabajo entre todos ellos. Esto también tendrá otro problema: el contexto y cualquier manipulación con entidades en el contexto o una conexión de base de datos utilizada por el contexto no es seguro para subprocesos.

Incluso para una aplicación de solo lectura, un contexto global no es una buena opción porque probablemente desee datos nuevos cada vez que consulte la aplicación.

+0

Gracias por su respuesta. ¿Quizás podrías explicar por qué es malo usar un único contexto global? Hace que el acceso paralelo sea más difícil, de seguro, pero ¿qué más ...? – Noldorin

+0

Ok, eso está mucho más claro ahora, gracias. Solo para confirmar, aunque un contexto global nunca es realmente apropiado, ¿un contexto único para un "diálogo de edición" o similar puede ser el camino correcto? En otras situaciones, como servicios web y ASP.NET, los contextos dentro de los métodos solo tienen más sentido. Sobre correcto? – Noldorin

+0

Tomé su consejo y eliminé el singelton. Ahora me sale otro error: http://stackoverflow.com/questions/14795899/an-entity-object-cannot-be-referenced-by-multiple-instances-of-ientitychangetrac –

61

De acuerdo con Daniel Simmons:

Create a new ObjectContext instance in a Using statement for each service method so that it is disposed of before the method returns. This step is critical for scalability of your service. It makes sure that database connections are not kept open across service calls and that temporary state used by a particular operation is garbage collected when that operation is over. The Entity Framework automatically caches metadata and other information it needs in the app domain, and ADO.NET pools database connections, so re-creating the context each time is a quick operation.

Se trata de su amplio artículo aquí:

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

creo que este consejo se extiende a las peticiones HTTP, por lo que sería válida para ASP.NET. Una aplicación stateful, fat-client como una aplicación WPF podría ser el único caso para un contexto "compartido".

+0

Gracias, esa es una cita muy informativa. Sin embargo, todavía me pregunto si un contexto compartido (global) sería apropiado incluso para una aplicación cliente de WPF o similar. ¿Hay * alguna * ventaja incluso en este caso? – Noldorin

+0

No habría ninguna ventaja para un contexto global en una aplicación de WPF, pero probablemente tampoco habría un perjuicio significativo. Si implementa un contexto global, es posible que deba realizar una administración manual de las conexiones de la base de datos (cierre explícito de la conexión) en casos de altas tasas de solicitud. –

+1

Derecha; así que, esencialmente, nunca puedo equivocarme al usar múltiples contextos temporales (dado que sé que está ocurriendo la agrupación de conexiones). ... Si estuvieras usando un solo contexto global, ¿no podría la conexión en teoría caer en un punto aleatorio en el tiempo? – Noldorin

2

El siguiente código ayudó a actualizar mi objeto con nuevos valores de base de datos. Las fuerzas de comando de entrada (objeto) .Reload() del objeto que recuerdan base de datos de valores

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

así como esto para colecciones (código VB): 'CType (myContext, IObjectContextAdapter) .ObjectContext.Refresh (RefreshMode.StoreWins, myCustomers)' –

6

accoriding a EF6 (4,5 también) Documentación: https://msdn.microsoft.com/en-us/data/hh949853#9

9,3 Contexto por solicitud

Los contextos de Entity Framework están destinados a ser utilizados como instancias efímeras para proporcionar la experiencia de rendimiento más óptima. Se espera que los contextos sean de corta duración y descartados, y como tales se han implementado para ser muy livianos y reutilizar los metadatos siempre que sea posible. En los escenarios web, es importante tener esto en cuenta y no tener un contexto por más tiempo que una sola solicitud. Del mismo modo, en escenarios no web, el contexto debe descartarse en función de su comprensión de los diferentes niveles de almacenamiento en caché en Entity Framework. En general, se debe evitar tener una instancia de contexto durante toda la vida de la aplicación, así como contextos por subproceso y contextos estáticos.

+0

Sé que esta respuesta ha estado aquí un tiempo, pero debo decir que esto me salvó un montón de dolor de cabeza Mantuvo el error de "Conexión compartida" al usar EF con Oracle, y no pudo entender por qué. Había establecido el dbContext como una variable de clase, instanciando en la creación. Cambiarlo a crear el contexto según sea necesario solucionó todos los males de mi mundo. ¡Gracias! – Fletchius