2010-12-15 20 views
28

Los objetos de contexto generados por Entity Framework no son seguros para subprocesos.Entity Framework Thread Safety

¿Qué sucede si utilizo dos contextos de entidad separados, uno para cada hilo (y llamo a SaveChanges() en cada uno)? ¿Esto será seguro para subprocesos?

// this method is called from several threads concurrently 
public void IncrementProperty() 
{ 
    var context = new MyEntities(); 

    context.SomeObject.SomeIntProperty++; 
    context.SaveChanges(); 
} 

creo marco marco de la entidad implementa algún tipo de variable 'contador', que realiza un seguimiento de si los valores actuales en el contexto son frescos o no.

  1. Con el código anterior - llamado desde hilos separados - ¿todavía necesito bloquear el incremento/guardar cambios?
  2. Si es así, ¿cuál es la forma preferida de lograr esto en este escenario simple?
+0

* "El contexto objetos generados por Entity Framework no es seguro para subprocesos. "* - ¿Por qué dices eso? – RPM1984

+0

Me refiero a MSDN: http://msdn.microsoft.com/en-us/library/system.data.objects.objectcontext.aspx donde dice "La clase ObjectContext no es segura para subprocesos". – Harper

+0

Sí, eso es lo que pensé que quería decir: el contexto, no las entidades. Por eso nunca debes usar un singleton para el OC. – RPM1984

Respuesta

31

Más que un hilo que opera en un solo contexto de Entity Framework no es seguro para subprocesos.

Una instancia separada de contexto para cada subproceso es segura para subprocesos. Mientras que cada hilo de ejecución tenga su propia instancia de contexto EF, estarás bien.

En su ejemplo, puede llamar a ese código de cualquier número de hilos al mismo tiempo y cada uno va a trabajar felizmente con su propio contexto.

Sin embargo, sugeriría la implementación de un bloque de 'usar' de la siguiente manera:

// this method is called from several threads concurrently 
public void IncrementProperty() 
{ 
    using (var context = new MyEntities()) 
    { 
     context.SomeObject.SomeIntProperty++; 
     context.SaveChanges(); 
    } 
} 
+0

Gracias. Entonces, ¿el valor real de SomeIntProperty se lee cuando haces SubmitChanges() o en qué momento? Quiero decir, si el primer subproceso incrementa el valor a 3, ¿el segundo subproceso tendrá aún el valor 2 en caché en alguna parte, o recuperará el valor en el lugar? – Harper

+0

Pasé por alto algunos aspectos importantes de su ejemplo. Primero, no tiene código que recupera e instancia 'SomeObject'. Entonces, como se muestra, el código no funcionará. No hay intercambio de cachés, búferes o bloqueos entre contextos. Por lo tanto, cada subproceso con su instancia de contexto se puede pensar de la misma manera que se podría pensar que el proceso se ejecuta en dos máquinas diferentes. Entonces, debe lidiar con los problemas de concurrencia de la base de datos en consecuencia. –

+1

Debería implementar una concurrencia optimista o una transacción de base de datos para tratar la base de datos de forma concurrente. –

0

Creo que "SomeObject.SomeIntProperty" es estático. Esto no tiene nada que ver con que la Entidad sea enhebrable. Si está escribiendo en variables estáticas en un entorno multiproceso, siempre debe envolverlos con un doble bloqueo de verificación para garantizar la seguridad del hilo.

0

Usted puede utilizar el enfoque de fábrica de inyectar su DbContext como una fábrica en vez de un per ejemplo, echar un vistazo a este : https://github.com/vany0114/EF.DbContextFactory

es más seguro y evitar a codificar la creación de la instancia en sus repositorios.

http://elvanydev.com/EF-DbContextFactory/

Hay una extensión a Ninject de hacerlo de una manera muy fácil, basta con llamar al método kernel.AddDbContextFactory<YourContext>(); también necesita cambiar su repositorio mediante la recepción de un Func<YourContext>