Saltar al contenido

Patrón de repositorio genérico para .net core con Dapper

Solución:

Teníamos un proyecto que teníamos un repositorio genérico elegante, pero después de que el proyecto evolucionó, tenemos abandonado el repositorio genérico para utilizar el poder real de dapper.

Recomendaría usar Dapper como directo sin operaciones CRUD genéricas.

Para demostrar lo que teníamos, proporcionaré un código de muestra que no está listo para producción y le dará una idea para implementar su propio repositorio genérico.

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

Repositorio genérico

public abstract class GenericRepository : IRepository 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(_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 [email protected]", new  ID = item.ID );
            
        

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

            using (IDbConnection cn = Connection)
            
                cn.Open();
                item = cn.Query("SELECT * FROM " + _tableName + " WHERE [email protected]", new  ID = id ).SingleOrDefault();
            

            return item;
        



        public virtual IEnumerable FindAll()
        
            IEnumerable items = null;

            using (IDbConnection cn = Connection)
            
                cn.Open();
                items = cn.Query("SELECT * FROM " + _tableName);
            

            return items;
        



    

Los ejemplos de @PathumLakshan solicitan los comentarios. Los ejemplos proporcionados se escriben de forma asincrónica, pero la fuente se puede implementar de forma síncrona. De todos modos, es solo una ilustración de cómo puede administrar la infraestructura con Dapper. Clase Db proporciona algunos métodos genéricos para obtener datos y ejecutar consultas SQL. Por ejemplo, puede usar sobrecarga Get(string, object) para consultas básicas, o tome Get(Func> para usar deja decir QueryMultiple. Clase Repository muestra, cómo puede verse el repositorio básico para la entidad Entity.

Db clase:

public class Db : IDb
{
    private readonly Func _dbConnectionFactory;

    public Db(Func dbConnectionFactory)
    
        _dbConnectionFactory = dbConnectionFactory ?? throw new ArgumentNullException(nameof(dbConnectionFactory));
    

    public async Task CommandAsync(Func> 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 GetAsync(Func> command)
    
        return await CommandAsync(command);
    

    public async Task> SelectAsync(Func>> 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 GetAsync(string sql, object parameters)
    
        return await CommandAsync(async (conn, trn, timeout) =>
        
            T result = await conn.QuerySingleAsync(sql, parameters, trn, timeout);
            return result;
        );
    

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

Repositorio clase:

public class Repository : IRepository

    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 FindByID(int id)
    
        return await _db.GetAsync("SELECT ... FROM ... WHERE Id = @id", new  id );
    

    public async Task> FindAll()
    
        return await _db.SelectAsync("SELECT ... FROM ... ", new  );
    

Db se puede ampliar con otro método genérico, por ejemplo, ExecuteScalar, que necesitaría en sus repositorios. Espero eso ayude.

Comentarios y calificaciones del post

Puedes asentar nuestra publicación exponiendo un comentario y dejando una valoración te damos las gracias.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *