2012-07-10 10 views
6

Estamos en un proceso de sustitución gradual del código de acceso a datos heredado por entidad de marco (4.3.1). En algunas ocasiones, no podemos evitar utilizar ambas formas de acceso a datos en una unidad de trabajo. Idealmente, esto debería hacerse en una transacción. Sin embargo, el código anterior usa SqlTransaction s que llama al Commit() cuando se realiza una unidad de trabajo y EF gestiona sus propias transacciones.Ignorar SqlTransaction.Commit dentro de TransactionScope

Así que pensamos en envolver el código "antiguo" y "nuevo" en un TransactionScope. Sin embargo, un Compromiso dentro de un entorno TransactionScope siempre se ejecuta, incluso si el TransactionScope no se completa. Este fragmento de código ilustra mi problema:

using (var conn = new SqlConnection("connection string")) 
{ 
    conn.Open(); 
    using (var scope = new TransactionScope()) 
    { 
    using (var tr = conn.BeginTransaction()) 
    { 
     using (var cmd = conn.CreateCommand()) 
     { 
     cmd.Transaction = tr; 
     cmd.CommandText = "some update statement"; 
     cmd.ExecuteNonQuery(); 
     } 
     tr.Commit(); 
    } 
    // In reality the code above is part of a legacy DAL, immutable. 
    // (can't insert SaveChanges before tr.Commit). 
    context.SaveChanges(); 
    if (<all ok>) // pseudo code for exception handling. 
     scope.Complete(); 
    } 
} 

La instrucción de actualización sigue apostando cuando scope.Complete() no es golpeado.

Así que, como parece, no puedo usar TransactionScope para forzar el código de acceso a datos anterior y SaveChanges desde un contexto para ejecutar en una transacción. ¿O hay alguna manera de anular la instrucción SqlTransaction.Commit?

Sé que hay más publicaciones aquí sobre TransactionScope y SqlTransaction, pero todas (con razón) dicen que usar SqlTransaction no es necesario (ni se recomienda) cuando se usa TransactionScope. Pero no usar SqlTransaction no es una opción aquí. Tenemos un marco heredado que compromete su propio SqlTransaction sy que no tiene una API para enganchar en su mecanismo de transacción.

+0

¿Al menos tiene acceso a la conexión? –

+0

@LadislavMrnka No, aparte de la cadena de conexión en el archivo de configuración. –

Respuesta

7

La declaración de actualización todavía se confirma cuando scope.Complete() no se golpea.

¡Oh no! El TransacationScope no se está utilizando .

Auto-alistar sólo funciona si la conexión está abierta después de (o dentro ) la TransactionScope.

Poner el Opendentro la TransactionScopedebe solucionar este problema (incluso con la transacción manual?) Como la conexión será entonces [generalmente] auto-dar de alta en el contexto TS ambiente.

Una conexión existente se puede alistar en el ámbito de transacción ambiente: connection.EnlistTransaction(Transaction.Current).

Alternativamente, el TS se puede crear a partir de una transacción existente, p. new TransactionScope(transaction), que puede o no ser útil aquí.

Creación de una operación manual si perfectamente bien, pero después de los TS (trampas se imaginaron!) Hace que se trata de transacciones simple y más fácil .. por lo menos en la mayoría de los casos :)

de codificación feliz!


El TS no se está utilizando para "la instrucción de actualización".Todavía [probablemente] se utilizará para context.SaveChanges(), ya que abrirá una nueva conexión que se enlistará automáticamente.

He proporcionado algunas de las opciones anteriores, aunque no estoy seguro acerca de la simple transacción "anidada". Ver el API (sellado?) Utilizado en contexto podría revelar más ideas sobre limitaciones/restricciones.

+0

¡Tienes razón! Cuando pongo el 'Abierto' después del TS, el TS está liderando. Y creo que en realidad esto también debería suceder, porque la conexión se abre dentro del viejo marco. Pero todavía se compromete. Tendré que profundizar un poco más en lo que está sucediendo allí y ver si una de sus sugerencias puede solucionar esto. Gracias, volveré a esto. –

+0

Esto me llevó por el camino correcto. Descubrí que el viejo marco deja las conexiones abiertas por más tiempo de lo que debería. Por lo tanto, es imposible utilizar TransactionScope de la manera que me gustaría sin cambiar el código anterior, algo que somos muy reacios a hacer. Me temo que tenemos que hacerlo. –

Cuestiones relacionadas