2009-03-24 4 views
7

Ich habe eine Situation (ich vermute, ist ziemlich Standard), wo ich einige Geschäftsberechnungen durchführen und eine Reihe von Datensätzen in der Datenbank erstellen muss. Wenn irgendwas schief geht, muss ich alles aus der Datenbank zurückholen. Offensichtlich brauche ich irgendeine Art von Transaktion. Meine Frage ist, wo ich die Transaktionsunterstützung implementiere. Hier ist mein BeispielVerwenden von Transaktionen mit Geschäftsprozessen und das Repository-Muster

//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); 
} 

Wenn eine der Updates der Datenbank fehlschlagen muss ich die anderen zurückrollen und raus. Muss ich aussetzen nur ein Connection-Objekt durch mein Repository, in dem ich

Connection.BeginTransaction() aufrufen können

oder mache ich, ich bestätigen nur in der Schicht Service und rufen nur eine Methode in das Repository, das alle spart die Objekte und behandelt die Transaktion? Das scheint mir nicht richtig zu sein. Es scheint, als würde es mich zwingen, in der Datenschicht zu viel Geschäftslogik zu machen.

Was ist der richtige Ansatz? Was ist, wenn ich Repositories überspannen muss (oder wäre das ein schlechtes Design)?

+1

+1, gute Frage. –

+0

Hoffentlich bekomme ich eine gute Antwort =). Eigentlich wäre jede Antwort zu diesem Zeitpunkt nett – Micah

Antwort

5

Ich nehme an, dass Sie .NET hier verwenden. In diesem Fall können Sie einfach den gesamten Codeabschnitt in eine using statement mit einer TransactionScope -Instanz umbrechen und die Transaktionssemantik für Sie übernehmen. Sie müssen einfach nur die Complete method am Ende nennen:

//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(); 
    } 
} 

Wenn eine Ausnahme auftritt, hat dies den Effekt von nicht Complete aufrufen, wenn der Code-Block verlassen wird; Die Dispose method auf der TransactionScope Implementierung der IDisposable interface wird aufgerufen, wenn der Gültigkeitsbereich der using Anweisung beendet wird.

Im Aufruf Dispose wird überprüft, ob die Transaktion abgeschlossen wurde (dieser Status wird festgelegt, wenn Complete erfolgreich ist). Wenn dieser Status nicht festgelegt ist, wird ein Rollback ausgeführt.

Sie können dies innerhalb anderer TransactionScope Instanzen verschachteln (tiefer in Ihrem Aufruf-Stack im selben Thread), um größere Transaktionen über mehrere Repositories hinweg zu erstellen.

+0

Also, was mache ich ziemlich Standard, und ist das die Lösung, die am häufigsten ist? – Micah

+0

@Micah: Angenommen, Sie verwenden .NET, ja, dies ist die bevorzugte Methode, wenn Sie eine Transaktion über mehrere Methoden/Objekte/Transaktions-Repositories erstrecken. – casperOne

+0

Super! Danke vielmals! – Micah

Verwandte Themen