2009-03-24 5 views
7

Tengo una situación (supongo que es bastante estándar) en la que necesito realizar algunos cálculos comerciales y crear un conjunto de registros en la base de datos. Si algo sale mal en algún momento, necesito retirar todo de la base de datos. Obvio, necesito algún tipo de transacción. Mi pregunta es dónde implemento el soporte de transacciones. Aquí está mi ejemploUso de transacciones con procesos empresariales y el patrón de repositorio

//BillingServices - This is my billing service layer. called from the UI 
public Result GenerateBill(BillData obj) 
{ 
    //Validate BillData 

    //Create a receivable line item in the receivables ledger 
    BillingRepository.Save(receivableItem); 

    //Update account record to reflect new billing information 
    BillingRepository.Save(accountRecord); 

    //...do a some other stuff 
    BillingRepository.Save(moreStuffInTheDatabase); 
} 

Si falla alguna de las actualizaciones de la base de datos, necesito retirar las demás y salir. No acabo de exponer un objeto de conexión a través de mi repositorio en el que puedo llamar

Connection.BeginTransaction()

o lo hago yo solo valido en la capa de servicio y a llamar un método en el repositorio que guarda toda los objetos y maneja la transacción? Esto no me parece muy bien. Parece que me obligaría a poner mucha lógica de negocios en la capa de datos.

¿Cuál es el enfoque correcto? ¿Qué pasa si necesito abarcar repositorios (o sería un mal diseño)?

+1

+1, buena pregunta. –

+0

Espero tener una buena respuesta =). En realidad, cualquier respuesta en este punto sería agradable – Micah

Respuesta

5

Supongo que está utilizando .NET aquí. Siendo ese el caso, puede simplemente envolver toda la sección de código en un using statement con una instancia TransactionScope y gestionará la semántica de la transacción por usted. Usted simplemente tiene que llamar a la Complete method al final:

//BillingServices - This is my billing service layer. called from the UI 
public Result GenerateBill(BillData obj) 
{ 
    // Create the transaction scope, this defaults to Required. 
    using (TransactionScope txScope = new TransactionScope()) 
    { 
      //Validate BillData 

      //Create a receivable line item in the receivables ledger 
      BillingRepository.Save(receivableItem); 

      //Update account record to reflect new billing information 
      BillingRepository.Save(accountRecord); 

      //...do a some other stuff 
      BillingRepository.Save(moreStuffInTheDatabase); 

      // Commit the transaction. 
      txScope.Complete(); 
    } 
} 

Si se produce una excepción, esto tiene el efecto de no llamar Complete cuando se sale del bloque de código; se llama al Dispose method en la implementación TransactionScope del IDisposable interface cuando se sale del alcance de la instrucción using.

En la llamada Dispose, comprueba si la transacción se completó (este estado se establece cuando Complete tiene éxito). Si ese estado no está configurado, realiza una reversión.

A continuación, puede anidar esto en otras instancias TransactionScope (más profundo en la pila de llamadas en el mismo subproceso) para crear transacciones más grandes en varios repositorios.

+0

Entonces, ¿qué es lo que estoy haciendo bastante estándar, y esta es la solución que es más común? – Micah

+0

@Micah: suponiendo que esté utilizando .NET, sí, este es el método preferido cuando desea expandir una transacción a través de múltiples métodos/objetos/repositorios transaccionales. – casperOne

+0

¡Impresionante! ¡Muchas gracias! – Micah

Cuestiones relacionadas