Использование транзакций с бизнес-процессами и шаблоном репозитория - PullRequest
7 голосов
/ 24 марта 2009

У меня есть ситуация (я полагаю, она довольно стандартная), когда мне нужно выполнить некоторые бизнес-вычисления и создать кучу записей в базе данных. Если что-то пойдет не так, мне нужно откатить все из базы данных. Обвиослы мне нужны какие-то сделки. У меня вопрос, где я могу реализовать поддержку транзакций. Вот мой пример

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

Если какое-либо из обновлений базы данных завершится неудачно, мне нужно откатить остальные и выйти. Должен ли я просто предоставить объект подключения через мой репозиторий, в котором я могу вызвать

Connection.BeginTransaction ()

или мне просто проверить на уровне сервиса и просто вызвать один метод в хранилище, который сохраняет все объекты и обрабатывает транзакцию? Это не совсем верно для меня. Похоже, это заставило бы меня заняться бизнес-логикой на уровне данных.

Какой правильный подход? Что если мне нужно охватить репозитории (или это будет плохой дизайн)?

1 Ответ

5 голосов
/ 24 марта 2009

Я предполагаю, что вы используете .NET здесь. В этом случае вы можете просто обернуть весь раздел кода в оператор using с экземпляром TransactionScope, и он будет обрабатывать семантику транзакции для вас. Вам просто нужно вызвать Complete метод в конце:

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

Если возникает исключение, это приводит к тому, что Complete не вызывается при выходе из блока кода; метод Dispose в реализации TransactionScope интерфейса IDisposable вызывается при выходе из области действия оператора using.

При вызове Dispose проверяется, завершена ли транзакция (это состояние устанавливается при успешном выполнении Complete). Если это состояние не установлено, выполняется откат.

Затем вы можете вложить это в другие TransactionScope экземпляры (глубже в стеке вызовов в том же потоке), чтобы создавать более крупные транзакции в нескольких репозиториях.

...