7

Tengo una aplicación que ejecuta varios subprocesos. Los hilos NO comparten un ObjectContext (cada hilo tiene el suyo, sé que no son seguros para hilos).Transacción de Entity Framework con varios subprocesos

Sin embargo, los hilos están operando bajo una transacción compartido. El hilo original crea un TransactionScope y cada hilo que genera crea un TransactionScope usando un DependentTransaction de la transacción en el hilo principal.

Cuando varias solicitudes ObjectContext ejecutar al mismo tiempo, a veces (no siempre) sale el error:

System.Data.EntityException occurred 
    Message=An error occurred while closing the provider connection. See the inner exception for details. 

    InnerException: System.Transactions.TransactionException 
     Message=The operation is not valid for the state of the transaction. 
     Source=System.Transactions 
     StackTrace: 
      at System.Transactions.TransactionStatePSPEOperation.get_Status(InternalTransaction tx) 
      at System.Transactions.TransactionInformation.get_Status() 
      at System.Data.ProviderBase.DbConnectionInternal.CloseConnection(DbConnection owningObject, DbConnectionFactory connectionFactory) 
      at System.Data.SqlClient.SqlInternalConnection.CloseConnection(DbConnection owningObject, DbConnectionFactory connectionFactory) 
      at System.Data.SqlClient.SqlConnection.Close() 
      at System.Data.EntityClient.EntityConnection.StoreCloseHelper() 
     InnerException: 

Sólo sé que se están ejecutando al mismo tiempo, porque cuando corro mis pruebas de unidad de depuración modo y esta excepción aparece, si miro los diferentes hilos que se están ejecutando, siempre veo al menos otro hilo detenido en una operación ObjectContext.

Además, después de hacer un poco de lectura, He intentado añadir multipleactiveresultsets=False a mi cadena de conexión y que no hizo ninguna diferencia.

Es esto un error en el marco de la entidad?

Respuesta

1

El problema se describe aquí:

http://www.b10g.dk/2007/09/07/dependenttransaction-and-multithreading/

Es bastante fácil para bloquear los SaveChanges y actualizar las llamadas, pero con el fin de asegurarse de que los bloqueos se producen durante la ejecución de consultas Tuve que crear un proveedor de consulta ficticio que se bloquea al ejecutar consultas. Realmente no debería haber tenido que hacer esto. Entity Framework debería haber sido lo suficientemente robusto como para manejar esto desde el primer momento ... especialmente teniendo en cuenta que no está destinado a manejar su propia creación de conexión.

Aquí es el código de la envoltura proveedor de consulta. Los IQueryables mismos y la clase QueryProvider base son reutilizables implementaciones sencillas basadas fuera de aquí http://blogs.msdn.com/b/mattwar/archive/2007/07/30/linq-building-an-iqueryable-provider-part-i.aspx

/// <summary> 
    /// A wrapper for queries executed by EF. 
    /// </summary> 
    internal class EntityFrameworkQueryProvider : QueryProvider 
    {  
     protected override object Execute(Expression expression) 
     { 
      try 
      { 
       // this is required due to a bug in how EF multi-threads when Transactions are used. 
       if (Transaction.Current != null) Monitor.Enter(EntityFrameworkExtensions.SyncRoot); 

       // enumerate is a simple extension method that forces enumeration of the IQueryable, thus making it actually get executed during the lock 
       return Expression.Lambda(expression).Compile().DynamicInvoke().Enumerate(); 
      } 
      finally 
      { 
       if (Transaction.Current != null) Monitor.Exit(EntityFrameworkRepositoryProvider.SyncRoot); 
      } 
     } 
    } 
+0

El enlace en el que basa su respuesta ya no funciona. ¿Puede proporcionar más información sobre la causa raíz? –

+1

La SyncRoot que utiliza para ingresar el bloqueo es diferente de la que está utilizando al salir. –

0

Si está pasando la misma instancia del clon dependiente a varios hilos, y luego deshacerse de ellos en cada hilo, eso podría llevar a un comportamiento como este (por ejemplo, al realizar una transacción finalizada y tal). AFAIK, necesitas un clon dependiente por hilo.

Otra posibilidad es que la transacción "padre" se está completada o eliminarse antes de que los hilos de terminar con su transacción. Asegúrese de que su trabajo asincrónico finalice antes de salir de TranscationScope principal (aunque esto se puede configurar para que bloquee transacciones inacabadas).

Lo sentimos, no tienen más que eso con lo que has descrito.

Buena suerte, Michael

+0

Todos mis transacciones sobre los nuevos temas son clones dependientes y el hilo padre no está completando la transacción antes de cualquiera de los procesos hijo . ¿Algún otro pensamiento? Gracias. – Jeff