En el artículo anterior conocimos y explicamos el patrón repositorio, vimos su propósito, su estructura, algunos casos comunes de uso, adicional creamos la estructura base en una solución de visual estudio, la cual seguiremos desarrollando a lo largo de este artículo y nos centraremos en la implementación de nuestros repositorios, recordemos que vamos a tener un repo para SqlServer, otro para MongoDB y otro para un Api "externa". Recordemos como va hasta el momento nuestra solución y nos enfocaremos en la parte señalada en rojo:
Para iniciar en el proyecto de Contrato vamos a crear las interfaces para cada repositorio, que definirán el contrato a implementar por los repositorios que vamos a crear o nuevos repos que puedan surgir en el futuro y que usen nuestras entidades de dominio Empleado, Artículo y DatosContacto, veamos entonces como quedan dichas interfaces:
public interface IEmpleadoRepository
{
List<Empleado> ObtenerEmpleados();
Empleado ObtenEmpleadoPoId(string id);
void GuardarEmpleado(Empleado empleado);
}
public interface IArticuloRepository
{
List<Articulo> ObtenerArticulos();
Articulo ObtenArticuloPorId(string id);
ICollection<Articulo> ObtenerArticulosPorIdEmpleado(string idEmpleado);
void GuardarArticulo(Articulo articulo);
}
public interface IDatosContactoRepository
{
DatosContacto ObtenerDatosContactoEmpleado(string idEmpleado);
}
Ahora procedemos a crear el repositorio para SqlServer, para esto agregamos la siguiente estructura en el proyecto SqlRepository:
Como podemos ver tenemos una clase llamada Contexto, la que representará nuestro contexto de Entity Framework para interactuar con nuestra base de datos en Sql Server, en esta ocasión usaremos el enfoque de EF llamado
Code First, si quieres profundizar más sobre este tema, te invito a leer
esta serie de post relacionados. Adicional en la raíz del proyecto también tenemos una clase llamada BaseRepository, la cual contiene todas las operaciones básicas que pueden aplicar para cualquier entidad que se tenga que interactúe con la base de datos. Vamos a ver el código de estas dos clases que menciono:
public partial class Contexto : DbContext
{
public Contexto()
: base("name=Contexto")
{
}
public virtual DbSet<Empleado.Empleado> Empleados { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Empleado.Empleado>()
.Property(e => e.Id)
.IsUnicode(false);
modelBuilder.Entity<Empleado.Empleado>()
.Property(e => e.Nombre)
.IsUnicode(false);
modelBuilder.Entity<Empleado.Empleado>()
.Property(e => e.Telefono)
.IsUnicode(false);
}
}
Tenemos el mapeo a la base de datos de la tabla Empleados, y tenemos algunas configuraciones a través de
Fluent Api para esta.
public class BaseRepository<T> where T : class
{
protected DbContext Contexto = new Contexto();
protected DbSet<T> DbSet;
public BaseRepository()
{
DbSet = Contexto.Set<T>();
}
public void Insertar(T entidad)
{
DbSet.Add(entidad);
}
public void Eliminar(T entidad)
{
DbSet.Remove(entidad);
}
public IQueryable<T> Filtrar(Expression<Func<T, bool>> expresion)
{
return DbSet.Where(expresion);
}
public T ObtenerPorId(string id)
{
return DbSet.Find(id);
}
public IQueryable<T> ObtenerTodos()
{
return DbSet;
}
public void GuardarCambios()
{
Contexto.SaveChanges();
}
}
Como mencioné antes nuestro repositorio base para Sql Server, nos permite usarlo con cualquier entidad de Code First y realizar algunas operaciones básicas como obtener todos los registros, obtener filtrando por id, realizar una consulta filtrada, insertar y eliminar.
Ahora vamos a observar las entidades que tenemos al interior de la carpeta Empleado, que son Empleado y EmpladoRepository. La clase empleado se encarga de mapear la tabla Empleados de la base de datos y EmpleadoRepository es el repositorio específico para realizar operaciones con la tabla Empleados y hereda de nuestro repositorio base para implementar las operaciones que este expone.
[Table("Empleados")]
public partial class Empleado
{
[StringLength(50)]
public string Id { get; set; }
[Required]
[StringLength(50)]
public string Nombre { get; set; }
[StringLength(10)]
public string Telefono { get; set; }
[StringLength(50)]
public string Direccion { get; set; }
}
Tenemos el mapeo de la tabla Empleados en nuestra base de datos y su configuración a través de
Data Anottations.
public class EmpleadoRepository : BaseRepository<Empleado>, IEmpleadoRepository
{
public List<Dominio.Empleado> ObtenerEmpleados()
{
AutoMapper.Mapper.CreateMap<Empleado, Dominio.Empleado>();
return
new List<Dominio.Empleado>(ObtenerTodos().AsEnumerable().Select(AutoMapper.Mapper.Map<Dominio.Empleado>
)).ToList();
}
public Dominio.Empleado ObtenEmpleadoPoId(string id)
{
var empleado = ObtenerPorId(id);
AutoMapper.Mapper.CreateMap<Empleado, Dominio.Empleado>();
return AutoMapper.Mapper.Map<Dominio.Empleado>(empleado);
}
public void GuardarEmpleado(Dominio.Empleado empleado)
{
AutoMapper.Mapper.CreateMap<Dominio.Empleado, Empleado>();
var emple = AutoMapper.Mapper.Map<Empleado>(empleado);
Insertar(emple);
}
}
Como podemos ver, el EmpleadoRepository hereda de BaseRepository usando la entidad Empleado para realizar las operaciones, adicional implementa la interfaz IEmpleadoRepository, que define el contrato a implementar para este repositorio. En este repositorio tenemos tres métodos, ObtenerEmpelados(), ObtenerEmpleadoPorId() y GuardarEmpleado() los cuales usan métodos del repositorio base respectivamente.
Por último algo curioso en este repositorio es el uso del AutoMapper, que es una herramienta que nos permite mapear dos objetos que pueden tener una estructura diferente pero contener todos o algunos datos iguales. En este caso lo usamos para mapear la entidad Empleados de CodeFirst a nuestra entidad de domino Empleado, que recordemos se encuentra en el proyecto de dominio, y es la entidad devuelta por el repositorio y usada por los clientes que consuman el repo, esto con el fin de que todos los clientes "hablen" en términos del domino y todo quede centralizado en estas entidades. Si quieres profundizar más acerca del tema AutoMapper puedes observar
este artículo del crack JulitoGTU.
Ahora ya tenemos listo el repositorio para interactuar con la base de datos Sql Server, es decir tenemos centralizada toda la lógica de acceso a datos en el repo, ahora podríamos consumir el repo a través de algún cliente (Aplicación web, escritorio, consola, etc.) para interactuar con la base de datos y estos no sabrían sobre la proveniencia de los datos.
Y bueno eso es todo por este artículo, en el cual implementamos el contrato de los repositorios y el repositorio especifico para acceso a datos de Sql Server usando
Entity Framework Code First, en el próximo artículo terminaremos los repositorios, implementando el repo para acceso a datos en MongoDB y también para obtener información del servicio web api. Espero sea de utilidad y de interés para ustedes.
Continua en:
Implementando patrón repositorio - Repository pattern en C# Parte III
Este ejemplo lo puedes descargar de
mi repositorio en GitHub