transaction transacciones practices net mvc framework best asp c# entity-framework transactions entity-framework-5 transactionscope

c# - transacciones - transaction entity framework 5



Ignorar TransactionScope para consultas específicas (3)

Estoy buscando una forma de ejecutar una consulta mientras un TransactionScope está activo e ignorar el TransactionScope. Básicamente, quiero ejecutar esta consulta en particular, sin importar qué.

Primero estoy usando el código de EF, y la forma en que está diseñada la aplicación, un nuevo contexto de datos se abre muchas veces en una sola llamada, cada una con sus propios cambios, y todas están contenidas en un único TransactionScope, que tiene Complete() Llamado al final suponiendo que no haya fallos. Dentro del contexto, hemos anulado SaveChanges para que, si ocurre alguna excepción en base.SaveChanges() , podamos capturarlo y registrarlo en la base de datos antes de deshacer la transacción.

Dado que SaveChanges ocurre dentro de la transacción, el registro obviamente no ocurre, porque pertenece a la misma transacción que la llamada original. Estoy tratando de ignorar el TransactionScope solo por el código de registro.

Aquí hay un código reducido:

// From the context public override int SaveChanges() { try { return base.SaveChanges(); } catch (Exception ex) { // Writes to the log table - I want this to run no matter what LogRepo.Log(/*stuff to log from the context*/); throw; } } // Inside the business logic public void DoSomething() { try { using (var scope = new TransactionScope()) { using (var context = new FooContext()) { // Do something context.SaveChanges(); } using (var context = new FooContext()) { // Do something else context.SaveChanges(); } scope.Complete(); } } catch (Exception ex) { // scope.Complete is never called, so the transaction is rolled back } }

Intenté usar ADO.NET normal en lugar de EF para el registro, pero sigo teniendo los mismos resultados: también se revierte.

Necesito que el manejo de errores ocurra dentro de SaveChanges , porque lo que estoy registrando es el estado de las entidades que se están SaveChanges , por lo que no puedo mover el registro fácilmente a otro lugar. Podría crear el mensaje dentro de la SaveChanges catch , lanzarlo y dejar que DoSomething catch registre, pero hay docenas de métodos de DoSomething , y prefiero tratar esto en un solo lugar.


Encontré una solución con la que no estoy realmente contento, pero parece funcionar. Al parecer, TransactionScope solo afecta al subproceso actual, por lo que el registro con un nuevo subproceso parece funcionar bien.

public override int SaveChanges() { try { return base.SaveChanges(); } catch (Exception ex) { string message = /*stuff to log from the context*/; new Thread(msg => { LogRepo.Log(msg); }).Start(message); throw; } }


Si ajusta su llamada de registro dentro de otro ámbito de transacción con la opción de supresión habilitada, no se utilizará el ámbito de transacción.

public override int SaveChanges() { try { return base.SaveChanges(); } catch (Exception ex) { using (var scope = new TransactionScope(TransactionScopeOption.Suppress)) { LogRepo.Log(message); // stuff to log from the context } throw; } }


Solo lo pensé inicialmente, pero debe colocar su LogRepo en su propio DataContext (DC2) para que el TransactionScope (con DC1) que lo rodea no lo deshaga cuando no esté comprometido.

Básicamente, necesita hacer que su registro sea autónomo y atómico.

EDITAR Al verlo un poco más, me parece que si movió su Cierre de sesión de SaveChanges al catch () en DoSomething (), su registro funcionará. Pero, su registro todavía necesita ser autocontenido y atómico.