1

ServiceStack을 사용하여 Rest 서비스를 구현 중입니다. 우리는 저장소 패턴과 자동 와이어 저장소를 IOC를 통해 서비스에 사용합니다.저장소 설계 : 트랜잭션 공유

현재 우리는 하나의 데이터베이스 모델이 하나의 저장소와 쌍을 이루는 간단한 접근 방식을 사용합니다. 즉, 하나의 서비스에서 두 개 이상의 엔터티가 조작 될 때마다 트랜잭션 경계가 사용되지 않습니다. 리포지토리는 순차적으로 호출됩니다. 하나 이상의 단계가 실패하면 수동으로 db를 초기 상태로 "롤백"해야합니다. 최악의 경우, 요청 스레드가 끊어 지거나 검사되지 않은 예외 (예 : OutOfMemoryException)가 발생하면 데이터베이스가 일관성없는 상태로 남습니다.

나는 가상 솔루션 세트를 가지고,하지만 난 적절한으로 아무도 생각하지 :

  1. 를 열고 연결 및 서비스 수준에서 거래를 시작합니다. 리포지토리를 호출하고 연결을 전달합니다. 이것은 분명히 모든 ddd 디자인 지침에 위배되므로 잘못되었습니다. 전체적인 요점은 상위 계층이 구체적인 지속성에 대해 완전히 모르는 것입니다. 게다가 단위 테스트가 엉망이됩니다.
  2. 첫 번째 저장소에서 트랜잭션을 시작하십시오. 다른 종속 리포지토리가 호출되지만 이미 열려있는 연결을 전달합니다. 이것은 또한 나쁜 디자인 같아 보입니다.
  3. 집합체 정의. 저는 도메인 모델링 전문가가 아니기 때문에이 하나의 위대한 팬이 아니며, 집계를 도입함으로써 디자인 오류를 도입 할 가능성이 있습니다. 현재 모델의 한 가지 장점은 간단하다는 것입니다.

이 문제에 대한 제안 사항이 있습니까? 미리 감사드립니다.

답변

2

일반적으로 UnitOfWork라는 통과 클래스를 사용할 수 있습니다.이 클래스에서는 "연결"을 열고 닫습니다. "Unit of work"를 검색하면 많은 예제를 찾을 수 있습니다. 아래 스 니펫을 맞춤 설정하여 거래를 포함 할 수 있습니다.

public class UnitOfWork : IUnitOfWork 
{ 
    readonly CompanyDbContext _context; 

    public UnitOfWork() 
    { 
     _context = new CompanyDbContext(); 
    } 

    private bool _disposed; 
    protected virtual void Dispose(bool disposing) 
    { 
     if (!_disposed) 
     { 
      if (disposing) 
      { 
       _context.Dispose(); 
      } 
     } 
     _disposed = true; 
    } 
    public void Dispose() 
    { 
     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 

    public void Save() 
    { 
     _context.SaveChanges(); 
    } 

    public IProductRepository ProductRepository 
    { 
     get { return new ProductRepository(_context); } 
    } 

    public ICartRepository CartRepository 
    { 
     get { return new CartRepository(_context); } 
    } 
} 

는 당신은 Ormlite 효과적으로 트랜잭션을 사용하기 위해서는

using (_unitOfWork) 
{ 
    var p = _unitOfWork.ProductRepository.SingleOrDefault(a => a.id ==1); 
    _unitOfWork.CartRepository.Add(p); 
    _unitOfWork.Save(); 
} 
1

아래, 당신은을 사용 (각 스레드에 대한 연결 개체를 저장할 수있는 사용자 정의 DBManager 클래스를 만들 필요가 같은 여러 트랜잭션을 수행 할 수 있습니다 ThreadStatic). 그런 다음 저장소에서이 사용자 정의 DBManager를 사용하여 다른 ormlite 함수를 호출 할 수 있습니다.

public class ThreadSpecificDBManager : IDisposable, IDBManager 
{ 
    [ThreadStatic] 
    private static int connectionCount = 0; 

    [ThreadStatic] 
    private static int transactionCount = 0; 

    [ThreadStatic] 
    private static IDbConnection connection = null; 

    public string ConnectionString { get; set; } 

    public IDbConnection Connection { get { EnsureOpenConnection(); return connection; } } 

    static ThreadSpecificDBManager() 
    { 
    } 

    private void EnsureOpenConnection() 
    { 
     if ((connection == null) || (connection.State == ConnectionState.Closed)) 
     { 
      OrmLiteConfig.TSTransaction = null; 
      transactionCount = 0; 
      connectionCount = 0; 

      connection = (DbConnection)ConnectionString.OpenDbConnection(); 

      //if (ConfigBase.EnableWebProfiler == true) 
      // connection = new ProfiledDbConnection((DbConnection)connection, MiniProfiler.Current); 
     } 
    } 

    public ThreadSpecificDBManager(string connectionString) 
    { 
     ConnectionString = connectionString; 
     connectionCount++; 
     EnsureOpenConnection(); 
    } 

    public void Dispose() 
    { 
     if (transactionCount > 0) 
     { 
      //Log.Error("Uncommitted Transaction is left"); 
     } 

     connectionCount--; 
     if (connectionCount < 1) 
     { 
      if ((connection != null) && (connection.State == ConnectionState.Open)) 
       connection.Close(); 

      if (connection != null) 
       connection.Dispose(); 

      connection = null; 
     } 
    } 

    public void BeginTransaction() 
    { 
     if (transactionCount == 0) 
     { 
      //Log.SqlBeginTransaction(0, true); 
      OrmLiteConfig.TSTransaction = Connection.BeginTransaction(); 
     } 
     else 
     { 
      //Log.SqlBeginTransaction(transactionCount, false); 
     } 
     transactionCount = transactionCount + 1; 
    } 

    public void RollbackTransaction() 
    { 
     try 
     { 
      if (transactionCount == 0) 
      { 
       //Log.SqlError("Transaction Rollback called without a begin transaction call."); 
       return; 
      } 

      if (OrmLiteConfig.TSTransaction == null) 
      { 
       //Log.SqlError("Transaction is not saved in the Thread Safe variable- so it cannot be rollbacked."); 
       throw new Exception("Transaction is not saved in the Thread Safe variable- so it cannot be rollbacked."); 
      } 

      if (transactionCount == 1) 
      { 
       transactionCount = 0; 
       try 
       { 
        //Log.SqlRollbackTransaction(transactionCount, true); 
        OrmLiteConfig.TSTransaction.Rollback(); 
       } 
       catch (Exception ex1) 
       { 
        //Log.SqlError(ex1,"Error when rolling back the transaction"); 
       } 

       OrmLiteConfig.TSTransaction.Dispose(); 
       OrmLiteConfig.TSTransaction = null; 
      } 
      else 
      { 
       //Log.SqlRollbackTransaction(transactionCount, false); 
       transactionCount = transactionCount - 1; 
      } 
     } 
     finally 
     { 

     } 
    } 

    public void CommitTransaction() 
    { 
     try 
     { 
      if (transactionCount == 0) 
      { 
       //Log.SqlError("Transaction Rollback called without a begin transaction call."); 
       return; 
      } 

      if (OrmLiteConfig.TSTransaction == null) 
      { 
       //Log.SqlError("Transaction is not saved in the Thread Safe variable- so it cannot be rollbacked."); 
       throw new Exception("Transaction is not saved in the Thread Safe variable- so it cannot be rollbacked."); 
      } 

      if (transactionCount == 1) 
      { 
       //Log.SqlCommitTransaction(transactionCount,true); 
       transactionCount = 0; 
       OrmLiteConfig.TSTransaction.Commit(); 
       OrmLiteConfig.TSTransaction.Dispose(); 
       OrmLiteConfig.TSTransaction = null; 
      } 
      else 
      { 
       //Log.SqlCommitTransaction(transactionCount, false); 
       transactionCount = transactionCount - 1 ; 
      } 
     } 
     finally 
     { 
     } 
    } 
} 
:

I가 사용하는 코드의 일부는 (제대로 작동하도록 코드를 수정해야합니다)

관련 문제