Как управлять транзакциями на уровне сервиса? - PullRequest
4 голосов
/ 01 февраля 2011

Мы разрабатываем приложение .Net со следующей архитектурой: уровень представления (с использованием шаблона MVC с ASP.Net MVC 2), уровень обслуживания, уровень доступа к данным (с использованием шаблона хранилища в Entity Framework).

Мы решили перевести управление транзакциями на уровень обслуживания, но не уверены, как его реализовать. Мы хотим полностью контролировать транзакцию на уровне сервисного уровня. То есть каждый раз, когда контроллер вызывает метод на уровне службы, он должен быть атомарной операцией в отношении обновлений базы данных.

Если бы не было связи между различными сервисами, предоставляемыми на уровне сервисов, то это было бы просто: каждый метод должен зафиксировать изменения в конце своего выполнения (то есть вызвать метод save в контексте, который он использует). Но иногда сервисы на уровне сервиса работают вместе.

например: мы предоставляем услугу отгрузки, которая имеет метод подтверждения, который получает следующие параметры: идентификатор отгрузки, флаг, указывающий, соответствует ли он новому или существующему клиенту, идентификатор клиента (в случае, если подтверждение отгрузки для существующего клиента) и имя клиента (в случае, если это для нового клиента). Если флаг установлен как «новый клиент», то сервисный уровень должен (а) создать клиента и (б) подтвердить отгрузку. Для (a) служба доставки вызывает службу поддержки клиентов (которая уже реализует проверки и логику, необходимые для создания нового клиента и сохранения его в базе данных).

Кто должен зафиксировать изменения в этом сценарии?

  • Должна ли служба поддержки сделать это? он не может зафиксировать изменения после создания нового клиента, потому что позже в методе подтверждения отгрузки что-то может пойти не так, но он должен зафиксировать свои изменения в случае, если это вызов напрямую (в другом случае использования, предусмотренном для создания клиента).
  • Должен ли контроллер, вызывающий метод service, делать это? но контроллер не должен ничего знать о транзакциях, мы решили поместить все знания транзакций на уровень обслуживания.
  • Менеджер транзакций на уровне сервисов? Как это оформить? Кто это называет и когда?

Существует ли шаблон проектирования для этого, которому мы должны следовать?

Ответы [ 2 ]

5 голосов
/ 03 февраля 2011

У меня есть Commit () на моем сервисе, он фиксируется, только если UnitOfWork создан сервисом, если он передается в конструктор, коммит ничего не делает.

Я использовал второй (внутренний) конструктор для сервиса:

public class MyService
{
private IUnitOfWork _uow;
private bool _uowInternal;

public MyService()
{
    _uow = new UnitOfWork();
    _uowInternal = false;
}

internal MyService(IUnitOfWork uow)
{
    _uow = uow;
    _uowInternal = true;
}
public MyServiceCall()
{
    // Create second service, passing in my UnitOfWork:
    var svc2 = new MySecondService(_uow);

    // Do your stuff with both services.
    ....
    // Commit my UnitOfWork, which will include all changes from svc2:
    Commit();
}

public void Commit()
{
    if(!_uowInternal)
        _uow.Commit();
}
}
1 голос
/ 01 февраля 2011

В аналогичной архитектуре с WCF и L2S вместо EF мы решили использовать транзакции в классе реализации основного интерфейса службы. Для достижения этой цели мы использовали TransactionScope :

public void AServiceMethod() {
    using(TransactionScope ts = new TransactionScope()) {
         service1.DoSomething();
         service2.DoSomething();
         ts.Complete();
    }
}

Основным недостатком является то, что транзакция может стать большой. В этом случае, если, например, для одного из вызовов службы в блоке транзакции требуется только доступ только для чтения, мы заключаем его во вложенный блок TransactionScope(TransactionScopeOption.Suppress), чтобы предотвратить дальнейшую блокировку строк / таблиц в течение времени жизни транзакции.

...