How to use Generic Repository Pattern with Dapper?

asp.net-core c# dapper generic-programming repository-pattern

Question

I adhered to a tutorial on the Generic Repository Pattern using ASP.NET core and EF CORE, such as here.

   public class Repository<T> : IRepository<T> where T : class
   {
    protected readonly DbContext _dbContext;
    protected readonly DbSet<T> _dbSet;

    public Repository(DbContext context)
    {
        _dbContext = context ?? throw new 
         ArgumentException(nameof(context));
        _dbSet = _dbContext.Set<T>();
    }

    public void Add(T entity)
    {
       _dbSet.Add(entity);
    }
   }

We can just utilize its predefined methods for inserting data since this is utilizing EF Core.Add way, but dapper requires a sql query, so how can I make this generic interface appropriate for Dapper?

1
9
9/20/2018 5:57:34 AM

Accepted Answer

The samples requested from the comments by @PathumLakshan. Examples given here are written asynchronously, however the source code may be implemented synchronously. In any case, it serves as a simple demonstration of how Dapper may be used to manage infrastructure. ClassDb offers a few general approaches for running SQL queries and obtaining data. As an illustration, overloadGet<T>(string, object) alternatively take the fundamental questionsGet<T>(Func<SqlConnection, SqlTransaction, int, Task<T>> example, let's sayQueryMultiple . ClassRepository<Entity> demonstrates how a simple entity repository may be viewed.Entity .

the Db range:

public class Db : IDb
{
    private readonly Func<SqlConnection> _dbConnectionFactory;

    public Db(Func<SqlConnection> dbConnectionFactory)
    {
        _dbConnectionFactory = dbConnectionFactory ?? throw new ArgumentNullException(nameof(dbConnectionFactory));
    }

    public async Task<T> CommandAsync<T>(Func<SqlConnection, SqlTransaction, int, Task<T>> command)
    {
        using (var connection = _dbConnectionFactory.Invoke())
        {
            await connection.OpenAsync();

            using (var transaction = connection.BeginTransaction())
            {
                try
                {
                    var result = await command(connection, transaction, Constants.CommandTimeout);

                    transaction.Commit();

                    return result;
                }
                catch (Exception ex)
                {
                    transaction.Rollback();
                    Logger.Instance.Error(ex);
                    throw;
                }
            }
        }
    }

    public async Task<T> GetAsync<T>(Func<SqlConnection, SqlTransaction, int, Task<T>> command)
    {
        return await CommandAsync(command);
    }

    public async Task<IList<T>> SelectAsync<T>(Func<SqlConnection, SqlTransaction, int, Task<IList<T>>> command)
    {
        return await CommandAsync(command);
    }

    public async Task ExecuteAsync(string sql, object parameters)
    {
        await CommandAsync(async (conn, trn, timeout) =>
        {
            await conn.ExecuteAsync(sql, parameters, trn, timeout);
                return 1;
        });

    public async Task<T> GetAsync<T>(string sql, object parameters)
    {
        return await CommandAsync(async (conn, trn, timeout) =>
        {
            T result = await conn.QuerySingleAsync<T>(sql, parameters, trn, timeout);
            return result;
        });
    }

    public async Task<IList<T>> SelectAsync<T>(string sql, object parameters)
    {
        return await CommandAsync<IList<T>>(async (conn, trn, timeout) =>
        {
            var result = (await conn.QueryAsync<T>(sql, parameters, trn, timeout)).ToList();
            return result;
        });
    }
}

Class Repository:

public class Repository<Entity> : IRepository<Entity>
{
    protected readonly IDb _db;

    public Repository(IDb db)
    {
        _db = db ?? throw new
            ArgumentException(nameof(db));
    }

    public async Task Add(Entity entity)
    {
        await _db.ExecuteAsync("INSERT INTO ... VALUES...", entity);
    }

    public async Task Update(Entity entity)
    {
        await _db.ExecuteAsync("UPDATE ... SET ...", entity);
    }

    public async Task Remove(Entity entity)
    {
        await _db.ExecuteAsync("DELETE FROM ... WHERE ...", entity);
    }

    public async Task<Entity> FindByID(int id)
    {
        return await _db.GetAsync<Entity>("SELECT ... FROM ... WHERE Id = @id", new { id });
    }

    public async Task<IEnumerable<Entity>> FindAll()
    {
        return await _db.SelectAsync<Entity>("SELECT ... FROM ... ", new { });
    }
}

Db may be expanded with more generic techniques, such asExecuteScalar in your repository, which you would need. Hope it's useful.

4
7/5/2019 11:09:50 PM

Popular Answer

Before the project progressed, we had a dapper generic repository, but now we have ditched the generic repository so we can use the full potential of dapper.

I advise using Dapper directly, avoiding generic CRUD operations.

I'll supply some example code to show you what we had, but it won't be production ready. This will give you some ideas on how to create your own generic repository.

public abstract class ConnectionBase : IDbConnection
{

    protected ConnectionBase(IDbConnection connection)
    {
        Connection = connection;
    }

    protected IDbConnection Connection { get; private set; }

    // Verbose but necessary implementation of IDbConnection:
    #region "IDbConnection implementation"

    public string ConnectionString
    {
        get
        {
            return Connection.ConnectionString;
        }

        set
        {
            Connection.ConnectionString = value;
        }
    }

    public int ConnectionTimeout
    {
        get
        {
            return Connection.ConnectionTimeout;
        }
    }

    public string Database
    {
        get
        {
            return Connection.Database;
        }
    }

    public ConnectionState State
    {
        get
        {
            return Connection.State;
        }
    }

    public IDbTransaction BeginTransaction()
    {
        return Connection.BeginTransaction();
    }



    public void Close()
    {
        Connection.Close();
    }

    public IDbCommand CreateCommand()
    {
        return Connection.CreateCommand();
    }

    public void Dispose()
    {
        Connection.Dispose();
    }

    public void Open()
    {
        Connection.Open();
    }

    #endregion
}

Generic Repository

public abstract class GenericRepository<T> : IRepository<T> where T : class //EntityBase, IAggregateRoot
    {

        private readonly string _tableName;


        internal IDbConnection Connection
        {
            get
            {
                return new SqlConnection(ConfigurationManager.ConnectionStrings["SmsQuizConnection"].ConnectionString);
            }
        }

        public GenericRepository(string tableName)
        {
            _tableName = tableName;
        }

        internal virtual dynamic Mapping(T item)
        {
            return item;
        }

        public virtual void Add(T item)
        {
            using (IDbConnection cn = Connection)
            {
                var parameters = (object)Mapping(item);
                cn.Open();
                item.ID = cn.Insert<Guid>(_tableName, parameters);
            }
        }

        public virtual void Update(T item)
        {
            using (IDbConnection cn = Connection)
            {
                var parameters = (object)Mapping(item);
                cn.Open();
                cn.Update(_tableName, parameters);
            }
        }

        public virtual void Remove(T item)
        {
            using (IDbConnection cn = Connection)
            {
                cn.Open();
                cn.Execute("DELETE FROM " + _tableName + " WHERE ID=@ID", new { ID = item.ID });
            }
        }

        public virtual T FindByID(Guid id)
        {
            T item = default(T);

            using (IDbConnection cn = Connection)
            {
                cn.Open();
                item = cn.Query<T>("SELECT * FROM " + _tableName + " WHERE ID=@ID", new { ID = id }).SingleOrDefault();
            }

            return item;
        }



        public virtual IEnumerable<T> FindAll()
        {
            IEnumerable<T> items = null;

            using (IDbConnection cn = Connection)
            {
                cn.Open();
                items = cn.Query<T>("SELECT * FROM " + _tableName);
            }

            return items;
        }



    }


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