Patrón Repository en C#

IObjectContext.cs

namespace Infrastructure.Contracts
{
    using System;

    /// <summary>
    /// Interfaz que encapsula firmas de métodos del contexto.
    /// </summary>
    public interface IObjectContext:IDisposable
    {
        /// <summary>
        /// Método para guardar cambios en el contexto.
        /// </summary>
        void SaveChanges();

        /// <summary>
        /// Método para revertir una transacción.
        /// </summary>
        void RollBack();
    }
}

 IObjectSetFactory.cs

namespace Infrastructure.Contracts
{
    using System;
    using System.Data.Entity;
    using System.Data.Entity.Core.Objects; 

    /// <summary>
    /// Interfaz que encapsula las firmas de los métodos de la fabrica encargada de gestionar la instancia
    /// de las entidades y su estado.
    /// </summary>
    public interface IObjectSetFactory: IDisposable
    {
        /// <summary>
        /// Método para crear objetos del contexto.
        /// </summary>
        /// <typeparam name="T">Tipo de entidad.</typeparam>
        /// <returns>Fabrica.</returns>
        IObjectSet<T> CreateObjectSet<T>() where T : class;

        /// <summary>
        /// Método para cambiar el estado de una entidad.
        /// </summary>
        /// <param name="entity">Entidad.</param>
        /// <param name="state">Estado.</param>
        void ChangeObjectState(object entity, EntityState state);
    }
}

 IRepository.cs

namespace Infrastructure.Contracts
{    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Linq.Expressions;    

    /// <summary>
    /// Interfaz que encapsula las firmas de los métodos del repositorio genérico.
    /// </summary>
    /// <typeparam name="T">Tipo de clase de la que se desea crear el repositorio.</typeparam>
    public interface IRepository<T> where T : class
    {        
        /// <summary>
        /// Método para agregar una entidad al contexto.
        /// </summary>
        /// <param name="entity">Entidad.</param>
        void Insert(T entity);        
        
        /// <summary>
        /// Método para eliminar una entidad del contexto.
        /// </summary>
        /// <param name="entity">Entidad.</param>
        void Delete(T entity);
        
        /// <summary>
        /// Método para actualizar una entidad del contexto.
        /// </summary>
        /// <param name="entity">Entidad.</param>
        void Update(T entity);
        
        /// <summary>
        /// Método para obtener una entidad que satisfaga una expresión lambda.
        /// </summary>
        /// <param name="where">Expresión lambda.</param>
        /// <param name="includeProperties">Propiedades de navegación que se desea incluir en la entidad.</param>
        /// <returns>Entidad.</returns>
        T Single(Expression<Func<T, bool>> where, params Expression<Func<T, object>>[] includeProperties);
        
        /// <summary>
        /// Método para obtener la primera entidad que satisface una expresión lambda.
        /// </summary>
        /// <param name="where">Expresión lambda.</param>
        /// <param name="includeProperties">Propiedades de navegación que se desea incluir en la entidad.</param>
        /// <returns>Entidad.</returns>
        T First(Expression<Func<T, bool>> where, params Expression<Func<T, object>>[] includeProperties);
        
        /// <summary>
        /// Método para obtener todos los registros de una entidad.
        /// </summary>
        /// <param name="includeProperties">Propiedades de navegación que se desea incluir en cada una de las entidades.</param>
        /// <returns>Conjunto de entidades.</returns>
        IEnumerable<T> GetAll(params Expression<Func<T, object>>[] includeProperties);

        /// <summary>
        /// Método para obtener todos aquellos registros de una entidad que satisfacen una expresión lambda.
        /// </summary>
        /// <param name="where">Expresión lambda.</param>
        /// <param name="includeProperties">Propiedades de navegación que se desea incluir en cada una de las entidades.</param>
        /// <returns>Entidades</returns>
        IEnumerable<T> Find(Expression<Func<T, bool>> where, params Expression<Func<T, object>>[] includeProperties);

        /// <summary>
        /// Método para obtener todos los registros de una entidad de forma paginada.
        /// </summary>
        /// <param name="pageNumber">Número de página.</param>
        /// <param name="pageSize">Tamaño de página.</param>
        /// <param name="totalPages">Total de páginas.</param>
        /// <param name="totalElements">Total de elementos.</param>
        /// <param name="orderBy">Criterio de ordenamiento y propiedad por la que se va a ordenar.</param>        
        /// <param name="includeProperties">Propiedades de navegación que se desea incluir en cada una de las entidades.</param>
        /// <returns>Conjunto de entidades paginadas.</returns>
        IEnumerable<T> GetAllWithPagination(int pageNumber, int pageSize, out int totalPages, out int totalElements, Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, params Expression<Func<T, object>>[] includeProperties);
        
        /// <summary>
        /// Método para obtener de forma paginada todos aquellos registros de una entidad que satisfacen una expresión lambda.
        /// </summary>
        /// <param name="pageNumber">Número de página.</param>
        /// <param name="pageSize">Tamaño de página.</param>
        /// <param name="totalPages">Total de páginas.</param>
        /// <param name="totalElements">Total de elementos.</param>
        /// <param name="where">Expresión lambda.</param>
        /// <param name="orderBy">Criterio de ordenamiento y propiedad por la que se va a ordenar.</param>        
        /// <param name="includeProperties">Propiedades de navegación que se desea incluir en cada una de las entidades.</param>
        /// <returns>Entidades.</returns>
        IEnumerable<T> FindWithPagination(int pageNumber, int pageSize, out int totalPages, out int totalElements, Expression<Func<T, bool>> where, Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, params Expression<Func<T, object>>[] includeProperties);
    }
}

IUnitOfWork.cs

namespace Infrastructure.Contracts
{
    /// <summary>
    /// Interfaz que encapsula las firmas de los métodos de la unidad de trabajo.
    /// </summary>
    public interface IUnitOfWork
    {        
        /// <summary>
        /// Método para comprometer una transacción.
        /// </summary>
        void Commit();
        
        /// <summary>
        /// Método para revertir una transacción.
        /// </summary>
        void RollBack();        
    }
}

DbContextAdapter.cs

namespace Infrastructure.Implementation
{    
    using Infrastructure.Contracts;
    using System.Collections.Generic;
    using System.Data.Entity;
    using System.Data.Entity.Core.Objects;
    using System.Linq;    
    
    /// <summary>
    /// Clase que encapsula un adaptador para el contexto de base de datos.
    /// </summary>
    public class DbContextAdapter : IObjectSetFactory, IObjectContext
    {
        // Variable que encapsula la instancia del contexto.        
        private readonly ObjectContext Context;        
        
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="context">Contexto.</param>
        public DbContextAdapter(DbContext context)
        {
            Context = context.GetObjectContext();
        }

        /// <summary>
        /// Método para guardar cambios en el contexto.
        /// </summary>
        public void SaveChanges()
        {
            Context.SaveChanges();
        }
        
        /// <summary>
        /// Método para revertir una transacción.
        /// </summary>
        public void RollBack()
        {
            IEnumerable<object> _objects = from e in Context.ObjectStateManager.GetObjectStateEntries(EntityState.Modified | EntityState.Deleted)
                                             select e.Entity;

            Context.Refresh(RefreshMode.StoreWins, _objects);

            IEnumerable<object> AddedCollection = from e in Context.ObjectStateManager.GetObjectStateEntries(EntityState.Added)
                                                  select e.Entity;

            foreach (object addedEntity in AddedCollection)
                Context.Detach(addedEntity);
        }
        
        /// <summary>
        /// Método para crear objetos del contexto.
        /// </summary>
        /// <typeparam name="T">Tipo de entidad.</typeparam>
        /// <returns>Fabrica.</returns>
        public IObjectSet<T> CreateObjectSet<T>() where T : class
        {
            return Context.CreateObjectSet<T>();
        }        
        
        /// <summary>
        /// Método para cambiar el estado de una entidad.
        /// </summary>
        /// <param name="entity">Entidad.</param>
        /// <param name="state">Estado.</param>
        public void ChangeObjectState(object entity, EntityState state)
        {
            Context.ObjectStateManager.ChangeObjectState(entity, state);
        }
        
        /// <summary>
        /// Método para liberar el contexto.
        /// </summary>
        public void Dispose()
        {
            Context.Dispose();
        }                
    }
}

DbContextExtensions.cs

namespace Infrastructure.Implementation
{    
    using System.Data.Entity;
    using System.Data.Entity.Core.Objects;
    using System.Data.Entity.Infrastructure;    

    /// <summary>
    /// Clase que contiene métodos de extensión del contexto.
    /// </summary>
    public static class DbContextExtensions
    {        
        /// <summary>
        /// Método para obtener la instancia del contexto.
        /// </summary>
        /// <param name="dbContext">Contexto.</param>
        /// <returns>Instancia del contexto.</returns>
        public static ObjectContext GetObjectContext(this DbContext dbContext)
        {
            return ((IObjectContextAdapter)dbContext).ObjectContext;
        }     
    }
}

Repository.cs

namespace Infrastructure.Implementation
{    
    using Infrastructure.Contracts;    
    using System;
    using System.Collections.Generic;
    using System.Data.Entity;
    using System.Data.Entity.Core.Objects;
    using System.Linq;
    using System.Linq.Expressions; 

    /// <summary>
    /// Clase que encapsula la implementación de los métodos del repositorio genérico.
    /// </summary>
    public class Repository<T> : IRepository<T> where T : class
    {        
        // Interface IObjectSet.        
        private readonly IObjectSet<T> ObjectSet;
		
        // Interface IObjectSetFactory.        
        private readonly IObjectSetFactory ObjectSetFactory;        
        
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="objectSetFactory">Fabrica de entidades.</param>
        public Repository(IObjectSetFactory objectSetFactory)
        {
            ObjectSet = objectSetFactory.CreateObjectSet<T>();
            ObjectSetFactory = objectSetFactory;
        }
        
        /// <summary>
        /// Método que proporciona una instancia para evaluar consultas.
        /// </summary>
        /// <returns>Instancia con funcionalidad para evaluar consultas.</returns>
        public IQueryable<T> AsQueryable()
        {
            return ObjectSet;
        }        
        
        /// <summary>
        /// Método para agregar una entidad al contexto.
        /// </summary>
        /// <param name="entity">Entidad.</param>
        public void Insert(T entity)
        {
            ObjectSet.AddObject(entity);
        }        
        
        /// <summary>
        /// Método para eliminar una entidad del contexto.
        /// </summary>
        /// <param name="entity">Entidad.</param>
        public void Delete(T entity)
        {
            ObjectSet.DeleteObject(entity);
        }

        /// <summary>
        /// Método para actualizar una entidad del contexto.
        /// </summary>
        /// <param name="entity">Entidad.</param>
        public void Update(T entity)
        {
            ObjectSet.Attach(entity);
            ObjectSetFactory.ChangeObjectState(entity, EntityState.Modified);
        }

        /// <summary>
        /// Método para obtener una entidad que satisfaga una expresión lambda.
        /// </summary>
        /// <param name="where">Expresión lambda.</param>
        /// <param name="includeProperties">Propiedades de navegación que se desea incluir en la entidad.</param>
        /// <returns>Entidad.</returns>
        public T Single(Expression<Func<T, bool>> where, params Expression<Func<T, object>>[] includeProperties)
        {
            IQueryable<T> _query = AsQueryable();
            _query = PerformInclusions(includeProperties, _query);
            return _query.Single(where);
        }

        /// <summary>
        /// Método para obtener la primera entidad que satisface una expresión lambda.
        /// </summary>
        /// <param name="where">Expresión lambda.</param>
        /// <param name="includeProperties">Propiedades de navegación que se desea incluir en la entidad.</param>
        /// <returns>Entidad.</returns>
        public T First(Expression<Func<T, bool>> where, params Expression<Func<T, object>>[] includeProperties)
        {
            IQueryable<T> _query = AsQueryable();
            _query = PerformInclusions(includeProperties, _query);
            return _query.FirstOrDefault(where);
        }

        /// <summary>
        /// Método para obtener todos los registros de una entidad.
        /// </summary>
        /// <param name="includeProperties">Propiedades de navegación que se desea incluir en cada una de las entidades.</param>
        /// <returns>Conjunto de entidades.</returns>
        public IEnumerable<T> GetAll(params Expression<Func<T, object>>[] includeProperties)
        {
            IQueryable<T> _query = AsQueryable();
            return PerformInclusions(includeProperties, _query);
        }

        /// <summary>
        /// Método para obtener todos aquellos registros de una entidad que satisfacen una expresión lambda.
        /// </summary>
        /// <param name="where">Expresión lambda.</param>
        /// <param name="includeProperties">Propiedades de navegación que se desea incluir en cada una de las entidades.</param>
        /// <returns>Entidades.</returns>
        public IEnumerable<T> Find(Expression<Func<T, bool>> where, params Expression<Func<T, object>>[] includeProperties)
        {
            IQueryable<T> _query = AsQueryable();
            _query = PerformInclusions(includeProperties, _query);
            return _query.Where(where);
        }

        /// <summary>
        /// Método para incluir en una consulta una o mas propiedades de navegación.
        /// </summary>
        /// <param name="includeProperties">Propiedades de navegación.</param>
        /// <param name="query">Consulta.</param>
        /// <returns>Consulta con las propiedades incluidas.</returns>
        private static IQueryable<T> PerformInclusions(IEnumerable<Expression<Func<T, object>>> includeProperties, IQueryable<T> query)
        {
            return includeProperties.Aggregate(query, (current, includeProperty) => current.Include(includeProperty));
        }

        /// <summary>
        /// Método para obtener todos los registros de una entidad de forma paginada.
        /// </summary>
        /// <param name="pageNumber">Número de página.</param>
        /// <param name="pageSize">Tamaño de página.</param>
        /// <param name="totalPages">Total de páginas.</param>
        /// <param name="totalElements">Total de elementos.</param>
        /// <param name="orderBy">Criterio de ordenamiento y propiedad por la que se va a ordenar.</param>        
        /// <param name="includeProperties">Propiedades de navegación que se desea incluir en cada una de las entidades.</param>
        /// <returns>Conjunto de entidades paginadas.</returns>
        public IEnumerable<T> GetAllWithPagination(int pageNumber, int pageSize, out int totalPages, out int totalElements, Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, params Expression<Func<T, object>>[] includeProperties)
        {
            if (pageNumber < 1 || pageSize < 1)
            {
                totalElements = 0;
                totalPages = 0;
                throw new ArgumentOutOfRangeException(null, "Los valores para número y tamaño de página deben ser mayores a 0.");
            }
            else
            {
                IQueryable<T> _query = AsQueryable();
                _query = PerformInclusions(includeProperties, _query);

                if (orderBy != null)
                    _query = orderBy(_query);

                totalElements = _query.Count();
                totalPages = CalculateTotalPages(_query.Count(), pageSize);

                return _query.Skip(GetSkip(pageNumber, pageSize)).Take(pageSize);
            }
        }

        /// <summary>
        /// Método para obtener de forma paginada todos aquellos registros de una entidad que satisfacen una expresión lambda.
        /// </summary>
        /// <param name="pageNumber">Número de página.</param>
        /// <param name="pageSize">Tamaño de página.</param>
        /// <param name="totalPages">Total de páginas.</param>
        /// <param name="totalElements">Total de elementos.</param>
        /// <param name="where">Expresión lambda.</param>
        /// <param name="orderBy">Criterio de ordenamiento y propiedad por la que se va a ordenar.</param>        
        /// <param name="includeProperties">Propiedades de navegación que se desea incluir en cada una de las entidades.</param>
        /// <returns>Entidades.</returns>
        public IEnumerable<T> FindWithPagination(int pageNumber, int pageSize, out int totalPages, out int totalElements, Expression<Func<T, bool>> where, Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, params Expression<Func<T, object>>[] includeProperties)
        {
            if (pageNumber < 1 || pageSize < 1)
            {
                totalPages = 0;
                totalElements = 0;
                throw new ArgumentOutOfRangeException(null, "Los valores para número y tamaño de página deben ser mayores a 0.");
            }
            else
            {
                IQueryable<T> _query = AsQueryable();
                _query = (PerformInclusions(includeProperties, _query)).Where(where);

                if (orderBy != null)
                    _query = orderBy(_query);

                totalElements = _query.Count();
                totalPages = CalculateTotalPages(_query.Count(), pageSize);

                return _query.Skip(GetSkip(pageNumber, pageSize)).Take(pageSize);
            }
        }

        /// <summary>
        /// Método para calcular el total de páginas.
        /// </summary>
        /// <param name="totalItems">Total de elementos.</param>
        /// <param name="pageSize">Tamaño de la página.</param>
        /// <returns>Total de páginas.</returns>
        private int CalculateTotalPages(int totalItems, int pageSize)
        {
            int _totalPages = -1;

            if (totalItems == 0)
                _totalPages = 0;
            else if ((totalItems % pageSize) == 0)
                _totalPages = totalItems / pageSize;
            else
                _totalPages = (totalItems / pageSize) + 1;

            return _totalPages;
        }

        /// <summary>
        /// Método para saber cuantos elementos se van a omitir.
        /// </summary>
        /// <param name="pageNumber">Número de página.</param>
        /// <param name="pageSize">Tamaño de la página.</param>
        /// <returns>Número de elementos que se deberan de omitir.</returns>
        private int GetSkip(int pageNumber, int pageSize)
        {
            return (pageSize * (pageNumber - 1));
        }
    }
}

UnitOfWork.cs

namespace Infrastructure.Implementation
{    
    using Infrastructure.Contracts;
    using System;    

    /// <summary>
    /// Clase que encapsula la implementación de los métodos de la unidad de trabajo.
    /// </summary>
    public class UnitOfWork : IUnitOfWork, IDisposable
    {        
        // Interface IObjectContext.        
        private readonly IObjectContext ObjectContext;        
        
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="objectContext">Instancia del contexto.</param>
        public UnitOfWork(IObjectContext objectContext)
        {
            ObjectContext = objectContext;
        }
        
        /// <summary>
        /// Método para comprometer una transacción.
        /// </summary>
        public void Commit()
        {
            ObjectContext.SaveChanges();
        }        
        
        /// <summary>
        /// Método para revertir una transacción.
        /// </summary>
        public void RollBack()
        {
            ObjectContext.RollBack();
        }		
        
        /// <summary>
        /// Método para liberar la instancia del contexto.
        /// </summary>
        public void Dispose()
        {
            if (ObjectContext != null)            
                ObjectContext.Dispose();            

            GC.SuppressFinalize(this);
        }        
    }
}

 

 

Comentarios (1) -

  • 326576 483400You will locate some fascinating points in time in this post but I do not know if I see all of them center to heart. There�s some validity but I will take hold opinion until I appear into it further. Wonderful post , thanks and we want significantly a lot more! Added to FeedBurner too 609577

Agregar comentario

Loading