2011-08-08 18 views
7

¿Cómo puedo realizar el equivalente a esto? My understanding is that this is impossible with TransactionScopes pero me gustaría llevar a cabo el equivalente de alguna otra manera:Transacciones anidadas en .NET

clase de lógica de negocios:

public bool Bar() 
{ 
    try 
    { 
    using (var tsWork = new TransactionScope()) 
    { 
     ComplicatedDataImportCode(somedata); 
     FlagRecordInDatabaseAsImported(); // this is the same record that's modified in the catch 
     tsWork.Complete(); 
     return true; 
    } 
    catch (DuplicateDataException err) 
    { 
     // if we got here, the above transaction should have rolled back, 
     // so take that same record in the database and update it to "Duplicate". 
     FlagSameRecordInDatabaseAsDuplicate(err.Message); 
    } 

    return false; 
} 

Ahora bien, esto funciona bien, hasta que encapsular todo esto dentro de una transacción (tal vez una prueba de integración que quiero revertir después de realizar afirmaciones).

simple prueba para probar mi punto:

public void CanTest() 
{ 
    // Arrange 
    var foo = new Foo(); 

    using (var ts = new TransactionScope()) 
    { 
    // Act 
    var success = foo.Bar(); 

    // Assert 
    if (success) 
    { 
     Assert.That(SomethingThatTestsThatTheDataWasImported); 
    } 
    else 
    { 
     Assert.That(SomethingThatTestsThatTheRecordWasMarkedAsDuplicate); 
    } 

    // Now that we have been able to perform our Asserts, rollback. 

    } 
} 

En última instancia, el código en Foo.Bar() puede ser modificado para dar cabida a una solución sin embargo, el código en ComplicatedDataImportCode() no puede ser modificado por esta solución, y es por lo tanto lo que realmente necesito asegurarme de que retroceda adecuadamente en el escenario de falla.

De nuevo, entiendo que TransactionScopes no se puede usar para hacer esto, de acuerdo con la publicación a la que hice referencia al principio de esta pregunta. Usé TransactionScopes aquí para indicar lo que quería hacer, y estoy buscando la mejor forma alternativa de implementar esta funcionalidad.

Respuesta

2

¿No es así que esto debe ser compatible con el DBMS que está utilizando?

SQL Server realmente no admite transacciones anidadas, por ejemplo, sin embargo, con SQL Server puede usar savepoints.

An article He escrito hace algunos años en mi blog.

+1

SQL Server admite transacciones anidadas, es solo que el primer 'ROLLBACK' mata todos los niveles. 'COMMIT' se rige por la anidación. – Kratz

+0

Hmm, tal vez estoy bajo el falso entendimiento de que SQL Server admite esto. Me gustaría aprender más. Leyendo tus enlaces +1 por ahora ... – Jaxidian

+0

@Kratz: Su comentario es exactamente mi problema. Quiero que 'ROLLBACK' solo revertir esa" transacción interna "específica en lugar de todo. – Jaxidian

1

Si usted puede obtener una bodega de la conexión de base de datos activa que ComplicatedDataImportCode está utilizando, sólo debería tener que ejecutar un BEGIN TRAN y ROLLBACK TRAN en esa conexión.

+0

Esto no permite una reversión parcial, sin embargo. La reversión condena toda la transacción y ese es el problema. Entonces, si hago lo que dices, cuando realice esa reversión, mi llamada a 'FlagSameRecordInDatabaseAsDuplicate' no funcionará porque está dentro de la misma transacción cuando la invoco mi método CanTest. – Jaxidian