작업 단위 (Unit of Work) : 더퍼 및 저장소 패턴 - C # .Net

.net c# dapper unit-of-work

문제

Dapper, Repositories, and Unit of Work 사용하여 좋은 솔루션을 개발하는 것은 나에게 어려운 과제였습니다. 저는 많은 연구 Unit of Work 클래스가 dictionary of repositories 가지고있는 구현을 보았습니다. 그것은 그것에 대해 올바른 방법으로 보이지 않습니다. 여기 내가하려는 일이있다.

UnitOfWork.cs

public interface IUnitOfWork
{
    SqlConnection GetConnection();

    SqlTransaction GetTransaction();

    void CommitChanges();
}

public class UnitOfWork : IUnitOfWork
{
    private SqlConnection connection;
    private SqlTransaction transaction;

    public SqlConnection GetConnection()
    {
        if (connection != null)
        {
            return connection;
        }

        connection = new SqlConnection(@"Data Source=");
        connection.Open();
        transaction = connection.BeginTransaction();
        return connection;
    }

    public SqlTransaction GetTransaction()
    {
        return this.transaction;
    }

    public void CommitChanges()
    {
        try
        {
            transaction.Commit();
        }
        catch
        {
            transaction.Rollback();
        }
        finally
        {
            transaction.Dispose();
            connection.Close();
        }
    }
}

나는 이것이 아마도 끔찍한 구현이라는 것을 알고 있지만, 나는 단지 기초를 세우려고하고있다.

다음은 서비스 구현 입니다. UnitOfWork 인스턴스가 서비스에 삽입되었습니다.

public class VeterinarianService : IVeterinarianService
{
    private readonly IClock clock;
    private readonly IUnitOfWork work;
    private readonly IVeterinarianRepository vetRepository;
    private readonly ITestingRepository testingRepository;


    public VeterinarianService(IClock clock, IUnitOfWork work, IVeterinarianRepository vetRepository, ITestingRepository testingRepository)
    {
        this.clock = clock;
        this.work = work;
        this.vetRepository = vetRepository;
        this.testingRepository = testingRepository;
    }

    /// <summary>
    /// Creates a veterinarian.
    /// </summary>
    /// <param name="newVetDTO">The newVetDTO containing all required parameters.</param>
    /// <returns>The newly created veterinarian.</returns>
    public async Task<VeterinarianDTO> CreateVeterinarian(NewVeterinarianDTO newVetDTO)
    {
        var now = clock.Now.ToDateTimeUtc();

        var vet = Mapper.Map<Veterinarian>(newVetDTO);
        var veterinarian = await vetRepository.Create(vet, now);
        // Call the second repository method here.

        // Commit the database changes from both repositories.
        this.work.CommitChanges();
        return Mapper.Map<VeterinarianDTO>(veterinarian);
    }
}

다음은 저장소 구현 입니다. 동일한 UnitOfWork 객체가이 저장소에 삽입된다는 점에 유의하십시오. 그것은 서비스 클래스에 주입 된 것과 동일한 UnitOfWork 입니다.

public class VeterinarianRepository : IVeterinarianRepository
{
    private readonly ICache cache;
    private readonly IUnitOfWork work;

    private readonly TimeSpan cacheTimeSpan = new TimeSpan(5, 0, 0);
    private const CommandType Type = CommandType.StoredProcedure;

    public VeterinarianRepository(ICache cache, IUnitOfWork work)
    {
        this.cache = cache;
        this.work = work;
    }

    public async Task<Veterinarian> Create(Veterinarian vet, DateTime date)
    {
            var connection = work.GetConnection();
            var parameters = new DynamicParameters();
            parameters.Add("@FirstName", vet.FirstName);
            parameters.Add("@LastName", vet.LastName);
            parameters.Add("@Date", date);
            parameters.Add("@User", 1);


            var identity = await connection.ExecuteScalarAsync<int?>("dbo.CreateVeterinarian", parameters, this.work.GetTransaction(), commandType: Type);

            if (identity.HasValue)
                vet.VeterinarianIdentity = identity.Value;
            else throw new Exception();
    }
}

내 생각 과정은 UnitOfWork 클래스의 동일한 인스턴스가 서비스와 기본 저장소에 injected 된다는 것입니다. 서비스는 동일한 connection / transaction 사용하여 여러 repositories 를 호출 할 수 있으며 모두 성공한 경우 전체 transaction commit 하거나 모든 것을 다시 롤백 할 수 있습니다. 이렇게하면 저장소의 변경 사항이 롤백됩니다.

두 가지 질문 :

  1. 그런 것을 구현하는 우스운 방법인가요?

  2. VeterinarianRepository 구현은 Create 메서드에서 UnitOfWork 인스턴스에 의해 생성 된 TransactionExecuteScalarAsync 메서드에 전달합니다. ExecuteScalarAsync 실행 된 후 트랜잭션이 완료된 것처럼 보입니다. "This SqlTransaction has completed; it is no longer usable." UnitOfWork CommitChanges() 메서드를 사용하려고 할 때 예외입니다. 나는 트랜잭션이 열려 있기를 기대하고 있었기 때문에 서비스가 그것을 필요로한다면 다른 몇몇 저장소에 의해 사용될 수 있었다.

인기 답변

서비스는 구성 또는 연결 서비스를 얻는 생성자를 포함하는 저장소를 용이하게해야합니다. 필자의 선택에 따라 해당 저장소의 구현은 영구 저장소 끝점 (또는 연결) 만 호출을 수행하는 데 필요한 방식으로 구축되어야합니다.

VeterinarianRepository 는 지속성에 대한 경로를 정의하는 구성과 특정 구현을 사용하여 명령을 수행하는 구현으로 만들어야합니다. 귀하의 VeterinarianRepository 에 대해 관리되거나 알려진 오케스트레이션은 없으며, 그것의 범위 밖입니다. 또한, 다시는 내 의견은, 당신의 VeterinarianService 관계없이 호출 방식의 기능을 할 수 있어야한다 VeterinarianRepository 않았다거나 작업입니다하지 않았다. 나는 이것이 dapper와 관련하여 도움이 될지 모르겠다. 그러나 자신의 강화 된 구현을 수행하는 ORM은 일반적인 저장소에 매우 친숙하지 않다 .



아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.
아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.