How to use Dapper with Repository Pattern / Unit of Work?

.net c# dapper unit-of-work

Question

Developing a sound resolution usingDapper, Repositories, and Unit of Work has been difficult for me. I've done extensive study and have seen instances when theUnit of Work has a classdictionary of repositories . That doesn't seem like the best course of action. What I'm attempting is as follows.

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

I'm aware that my implementation is probably bad, but I'm simply attempting to lay the groundwork.

Here's a 30 zzz and zzz. The service has received the injection of the UnitOfWork instance.

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

The implementation of a repository is shown below. Be aware that the sameUnitOfWork This repository is injected with an object. It is identical.UnitOfWork that the service class received an injection of.

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

Here, I'm thinking that the identical case of theUnitOfWork There will beinjected both the underlying repository and the service. A service may make many calls.repositories using similarconnection / transaction and if all went well, it cancommit the wholetransaction or reverse the whole process. Any modification made by any of the repositories would be undone by doing this.

Two inquiries:

  1. Is this a foolish method to put this into practice?

  2. My VeterinarianRepository implementation, in the Create method, I pass theTransaction developed by theUnitOfWork as an exampleExecuteScalarAsync a technique.ExecuteScalarAsync executes, yet it seems that the transaction is finished. I obtain a"This SqlTransaction has completed; it is no longer usable." while attempting to utilize theUnitOfWork CommitChanges() method. If the service needed it, I had anticipated that the transaction would remain open such that it may be accessed by a few additional repositories.

1
3
10/11/2016 5:49:01 PM

Popular Answer

Your service needs to make it easier for a repository to have a constructor that requests a connection or configuration service. In my opinion, the persistent storage endpoint (or connection) should be the sole need for calls to be performed in the repository's implementation.

Your VeterinarianRepository should be built with a configuration that specifies the implementation's route to persistence and how the command will be executed. There is no controlled or known orchestration for yourVeterinarianRepository beyond the purview of its job. Additionally, in my view, yourVeterinarianService should be able to operate no matter how the invokedVeterinarianRepository did or didn't do its task. I'm not sure whether this is relevant to dapper, but it is relevant to generic services.

0
10/11/2016 8:59:41 PM


Related Questions





Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow