4

우리는 프레젠테이션 계층 (ASP.Net MVC 2와 MVC 패턴 사용), 서비스 계층, 데이터 액세스 계층 (Entity Framework의 저장소 패턴 사용)과 같은 .Net 응용 프로그램을 개발 중입니다.서비스 계층에서 트랜잭션을 관리하는 방법은 무엇입니까?

우리는 트랜잭션 관리를 서비스 계층에 넣기로 결정했으나 구현 방법에 대해서는 확실하지 않습니다. 우리는 서비스 계층 레벨에서 트랜잭션을 완전히 제어하려고합니다. 즉, 컨트롤러가 서비스 계층에서 메소드를 호출 할 때마다 데이터베이스 업데이트에 관한 원자 적 조작이어야합니다.

서비스 계층에서 제공되는 서로 다른 서비스간에 관계가 없으면 간단합니다. 각 메소드는 실행이 끝날 때 변경 사항을 커밋해야합니다 (즉, 사용하는 컨텍스트에서 save 메소드를 호출해야 함) . 그러나 때로는 서비스 계층의 서비스가 함께 작동합니다.

예 : 우리는 다음 매개 변수를받는 확인 서비스 방법을 제공합니다 : 선적 ID, 새로운 고객 또는 기존 고객에 해당하는지 여부를 나타내는 플래그, 고객 ID (발송 확인 기존 고객을위한 것임) 및 고객 이름 (신규 고객을위한 경우). 플래그가 "신규 고객"으로 설정된 경우, 서비스 계층은 (a) 고객을 생성하고 (b) 선적을 확인해야합니다. (a) 발송 서비스는 고객 서비스 (새 고객을 생성하고 데이터베이스에 저장하는 데 필요한 검증 및 논리를 이미 구현 한 고객 서비스)를 호출합니다.

누가이 시나리오에서 변경을 적용해야합니까?

  • 고객 서비스를 받아야합니까? 새 고객을 만든 후에는 변경 사항을 적용 할 수 없습니다. 왜냐하면 배송 확인 방법에서 나중에 잘못 될 수 있기 때문에 직접 호출하는 경우 (클라이언트를 만들기 위해 제공되는 다른 사용 사례에서) 변경 사항을 커밋해야합니다.
  • 서비스 메소드를 호출하는 컨트롤러가해야합니까? 그러나 컨트롤러는 트랜잭션에 대해 알지 않아야합니다. 우리는 모든 트랜잭션 노벨 드를 서비스 계층에 넣기로 결정했습니다.
  • 서비스 계층의 트랜잭션 관리자? 그것을 디자인하는 방법?, 누가 그것을 부르는가?

따라야 할 디자인 패턴이 있습니까?

답변

5

내 서비스에 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(); 
} 
} 
+0

감사합니다 존 :

나는 서비스에 대한 두 번째 (내부) 생성자를 사용! 정확히 내가 찾던 대답의 종류. – mmutilva

1

EF 대신 WCF 및 L2S와 유사한 아키텍처에서 우리는 주 서비스 인터페이스 구현 클래스에서 트랜잭션을 사용하기로 결정했습니다. 우리는이를 달성하기 위해 TransactionScope을 사용 :

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

가장 큰 단점은 트랜잭션이 커질 수 있다는 것이다. 이 경우 예를 들어 트랜잭션 블록의 서비스 호출 중 읽기 전용 액세스 만 필요하면 중첩 된 TransactionScope(TransactionScopeOption.Suppress) 블록으로 래핑하여 트랜잭션 수명에서 행/테이블을 더 이상 잠글 수 없도록 차단합니다.