2011-02-26 22 views
7

Estoy evaluando EF para mis próximas aplicaciones nuevas.Cómo cambiar globalmente IsolationLevel de todas las transacciones de Entity Framework

¿Cómo puedo cambiar globalmente el IsolationLevel de todas las transacciones de EF en una aplicación? Ej .: Supongamos que quiero usar "Leer captura confirmada".

Si bien es correcto especificar IsolationLevel cuando explícitamente necesito un TransactionScope de todos modos (vea el código a continuación), sería feo tener que encapsular cada operación de salvar EF en un TransactionScope.

'OK 
    Using tsc As New TransactionScope(TransactionScopeOption.RequiresNew, TransactionOption.ReadCommitted) 
     UpdateShoppingCart 
     EnqueueNewOrder 
     SendConfirmationEmail 
     tsc.Complete 
    End Using 

    'Is this really the only way to avoid Serializable? 
    Using tsc As New TransactionScope(TransactionScopeOption.RequiresNew, TransactionOption.ReadCommitted) 
     _ctx.SaveChanges() 
     tsc.Complete 
    End Using 

    Class TransactionOption 
     Public Shared ReadOnly ReadCommitted As New TransactionOptions() With { 
      .IsolationLevel = IsolationLevel.ReadCommitted, 
      .Timeout = TransactionManager.DefaultTimeout 
      } 
    End Class 

Supongo que mezclar IsolationLevles no es una buena idea. ¿Me equivoco con eso?

Con Serializable y SQL Server (a diferencia de Oracle) la inserción de una simple lectura inocente puede provocar un bloqueo de conversión.

Desde el FAQ EF: "Se recomienda el uso de transacciones de lectura comprometido y su utilización Lea aislamiento de instantánea COMPROMETIDOS si es necesario tener lectores no bloquean a los escritores y los escritores no bloquear los lectores."

No entiendo por qué EF se establece en Serializable y hace que sea tan difícil cambiar el nivel de aislamiento predeterminado - con SQL Server (en contraste con Oracle de múltiples versiones) predeterminado a un modelo de simultaneidad pesimista. Una opción de configuración debería ser muy fácil de implementar, ¿o me falta algo aquí?

+2

¿Dónde encontraste que EF tiene el valor predeterminado Serializable? –

Respuesta

9

Estoy casi seguro de que el nivel de aislamiento de transacción EF predeterminado se basa en el proveedor de base de datos usado. SaveChanges ejecuta este código:

... 
    try 
    { 
     this.EnsureConnection(); 
     flag = true; 
     Transaction current = Transaction.Current; 
     bool flag2 = false; 
     if (connection.CurrentTransaction == null) 
     { 
      flag2 = null == this._lastTransaction; 
     } 
     using (DbTransaction transaction = null) 
     { 
      if (flag2) 
      { 
       transaction = connection.BeginTransaction(); 
      } 
      objectStateEntriesCount = this._adapter.Update(this.ObjectStateManager); 
      if (transaction != null) 
      { 
       transaction.Commit(); 
      } 
     } 
    } 
    ... 

Como se puede ver BeginTransaction se llama sin IsolationLevel especificado. Debajo del capó crea una transacción específica del proveedor con IsolationLevel.Unspecified. El nivel de aislamiento no especificado debe dar como resultado un nivel de aislamiento predeterminado para el servidor/controlador de la base de datos. En el nivel de aislamiento predeterminado de SQL Server es READ COMMITED, por lo que espero que debería usarlo, pero aún no lo he probado.

Si desea globalmente nivel de aislamiento de cambio puede anular SaveChanges en su clase derivada de ObjectContext y envolver base.SaveChanges() en la costumbre TransactionScope.

+0

Tiene razón, mi suposición era incorrecta. Tal vez tropecé con el siguiente problema al probar: http://connect.microsoft.com/SQLServer/feedback/details/243527/sp-reset-connection-does-reset-isolation-level Comprobé que el valor predeterminado de EF con SQL Server es "Read Committed" haciendo primero una SqlConnection.ClearAllPools() y consultando con SQLProfiler . –

0

Puede haber una limitación en VB pero en C# que lo haría así:

TransactionOptions transactionOptions = GetTransactionOptions(); 
new TransactionScope(TransactionScopeOption.RequiresNew, transactionOptions) 

Tenga en cuenta que el segundo parámetro es transactionOptions, esto puede ser creado de la siguiente manera:

public TransactionOptions GetTransactionOptions() 
    { 
     TransactionOptions transactionOptions = new TransactionOptions(); 
     transactionOptions.IsolationLevel = IsolationLevel.ReadCommitted; 
     return transactionOptions; 
    } 

Al poner el código anterior en un método de Fábrica, y llamando a ese método de fábrica cada vez que necesite opciones de transacción, puede tener un lugar para cambiar todos los ámbitos de transacción en su solución.

+1

Eso es exactamente lo que hice en el código publicado en mi pregunta :-) Estoy buscando una manera de no tener que adjuntar cada .SaveChanges con un TransactionScope para cambiar la instantánea Serializable a Read Committed de EF predeterminada. –

Cuestiones relacionadas