1: Interfaz IBaseDAL
La interfaz base para el acceso a datos:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
namespace ArquitecturaTresCapas.IDAL
{
public interface IRepositorioBase<t> where T : class
{
int GuardarCambios();
void Agregar(T entidad);
void Eliminar(T entidad);
void EliminarPor(Expression<func bool="">> condicionEliminacion);
void Modificar(T entidad, params string[] nombresPropiedades);
IQueryable<t> Donde(Expression<func bool="">> expresionLambda);
IQueryable<t> DondeOrdenarPor<tkey>(Expression<func bool="">> expresionLambda, Expression<func tkey="">> selectorClave, bool ascendente = true);
IQueryable<t> DondeIncluir(Expression<func bool="">> expresionLambda, params string[] nombresPropiedadesIncluidas);
IQueryable<t> DondeIncluirOrdenarPor<tkey>(Expression<func bool="">> expresionLambda, Expression<func tkey="">> selectorClave, bool ascendente = true, params string[] nombresPropiedadesIncluidas);
IEnumerable<t> DondePaginar<tkey>(int indicePagina, int tamanoPagina, out int totalRegistros, Expression<func bool="">> expresionLambda, Expression<func tkey="">> selectorClave, bool ascendente = true, params string[] nombresPropiedadesIncluidas);
IQueryable<t> ConsultarPorSql(string consultaSql, params System.Data.SqlClient.SqlParameter[] parametros);
}
}
</t></func></func></tkey></t></func></func></tkey></t></func></t></func></func></tkey></t></func></t></func></t>
Plantilla T4 generadora de interfaces:
<#@ template language="C#" debug="false" hostspecific="true"#>
<#@ include file="EF.Utility.CS.ttinclude"#>
<#@ output extension=".cs"#>
<#
CodeGenerationTools codigo = new CodeGenerationTools(this);
MetadataLoader cargador = new MetadataLoader(this);
CodeRegion region = new CodeRegion(this, 1);
MetadataTools ef = new MetadataTools(this);
string archivoEntrada1 = @"R:\Proyectos\ArquitecturaTresCapas\Modelo\Modelo.edmx";
EdmItemCollection ColeccionElementos1 = cargador.CreateEdmItemCollection(archivoEntrada1);
string espacioNombres = codigo.VsNamespaceSuggestion();
EntityFrameworkTemplateFileManager gestorArchivos = EntityFrameworkTemplateFileManager.Create(this);
#>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ArquitecturaTresCapas.Modelo;
namespace ArquitecturaTresCapas.IDAL
{
<#
foreach (EntityType entidad in ColeccionElementos1.GetItems<entitytype>().OrderBy(e => e.Nombre))
{
#>
public partial interface I<#=entidad.Nombre#>Repositorio : IRepositorioBase<<#=entidad.Nombre#>>{ }
<#}#>
}
</entitytype>
Código generado:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ArquitecturaTresCapas.Modelo;
namespace ArquitecturaTresCapas.IDAL
{
public partial interface ICompraRepositorio : IRepositorioBase<compra>{ }
public partial interface IMenuRepositorio : IRepositorioBase<menu>{ }
public partial interface IProductoRepositorio : IRepositorioBase<producto>{ }
public partial interface IRolRepositorio : IRepositorioBase<rol>{ }
public partial interface IRolMenuRepositorio : IRepositorioBase<rolmenu>{ }
public partial interface IUsuarioRolRepositorio : IRepositorioBase<usuariorol>{ }
public partial interface IUsuarioRepositorio : IRepositorioBase<usuario>{ }
}
</usuario></usuariorol></rolmenu></rol></producto></menu></compra>
2: Capa de Acceso a Datos (DAL)
Implementación base del repositorio:
using System;
using System.Collections.Generic;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Linq.Expressions;
namespace ArquitecturaTresCapas.DAL
{
using ArquitecturaTresCapas.IDAL;
using InyeccionDependencias;
using System.Data.Entity;
public class RepositorioBase<t> : IRepositorioBase<t> where T : class
{
private DbContext contexto;
public RepositorioBase()
{
contexto = FactoriaContextoDbContext.ObtenerDbContext();
}
#region Guardar cambios en la base de datos
public int GuardarCambios()
{
return contexto.SaveChanges();
}
#endregion
#region Agregar entidad
public void Agregar(T entidad)
{
contexto.Set<t>().Add(entidad);
}
#endregion
#region Eliminar entidad
public void Eliminar(T entidad)
{
DbEntityEntry entrada = contexto.Entry<t>(entidad);
entrada.State = System.Data.Entity.EntityState.Deleted;
}
#endregion
#region Eliminar por condición
public void EliminarPor(Expression<func bool="">> condicionEliminacion)
{
var listaEliminacion = contexto.Set<t>().Where(condicionEliminacion);
foreach (T entidad in listaEliminacion)
{
Eliminar(entidad);
}
}
#endregion
#region Modificar entidad
public void Modificar(T entidad, params string[] nombresPropiedades)
{
DbEntityEntry entrada = contexto.Entry<t>(entidad);
entrada.State = System.Data.Entity.EntityState.Unchanged;
foreach (string nombrePropiedad in nombresPropiedades)
{
entrada.Property(nombrePropiedad).IsModified = true;
}
}
#endregion
#region Consultar entidades
public IQueryable<t> Donde(Expression<func bool="">> expresionLambda)
{
return contexto.Set<t>().Where(expresionLambda);
}
#endregion
#region Consultar con ordenamiento
public IQueryable<t> DondeOrdenarPor<tkey>(Expression<func bool="">> expresionLambda, Expression<func tkey="">> selectorClave, bool ascendente = true)
{
if (ascendente)
return contexto.Set<t>().Where(expresionLambda).OrderBy(selectorClave);
else
return contexto.Set<t>().Where(expresionLambda).OrderByDescending(selectorClave);
}
#endregion
#region Consultar con include
public IQueryable<t> DondeIncluir(Expression<func bool="">> expresionLambda, params string[] nombresPropiedadesIncluidas)
{
DbQuery<t> consultaDb = contexto.Set<t>();
foreach (string nombreIncluir in nombresPropiedadesIncluidas)
{
consultaDb = consultaDb.Include(nombreIncluir);
}
return consultaDb.Where(expresionLambda);
}
#endregion
#region Consultar con include y ordenamiento
public IQueryable<t> DondeIncluirOrdenarPor<tkey>(Expression<func bool="">> expresionLambda, Expression<func tkey="">> selectorClave, bool ascendente = true, params string[] nombresPropiedadesIncluidas)
{
DbQuery<t> consultaDb = contexto.Set<t>();
if (nombresPropiedadesIncluidas != null && nombresPropiedadesIncluidas.Length > 0)
{
foreach (string nombreIncluir in nombresPropiedadesIncluidas)
{
consultaDb = consultaDb.Include(nombreIncluir);
}
}
IQueryable<t> consulta = consultaDb.Where(expresionLambda);
if (ascendente)
return consulta.OrderBy(selectorClave);
else
return consulta.OrderByDescending(selectorClave);
}
#endregion
#region Consulta paginada con include y ordenamiento
public IEnumerable<t> DondePaginar<tkey>(int indicePagina, int tamanoPagina, out int totalRegistros, Expression<func bool="">> expresionLambda, Expression<func tkey="">> selectorClave, bool ascendente = true, params string[] nombresPropiedadesIncluidas)
{
DbQuery<t> consultaDb = contexto.Set<t>();
if (nombresPropiedadesIncluidas != null && nombresPropiedadesIncluidas.Length > 0)
{
foreach (string nombreIncluir in nombresPropiedadesIncluidas)
{
consultaDb = consultaDb.Include(nombreIncluir);
}
}
IOrderedQueryable<t> consultaOrdenada = null;
if (ascendente)
{
consultaOrdenada = consultaDb.OrderBy(selectorClave);
}
else
{
consultaOrdenada = consultaDb.OrderByDescending(selectorClave);
}
var lista = consultaOrdenada.Where(expresionLambda).Skip((indicePagina - 1) * tamanoPagina).Take(tamanoPagina).ToList();
totalRegistros = consultaOrdenada.Where(expresionLambda).Count();
return lista;
}
#endregion
#region Consulta por SQL
public IQueryable<t> ConsultarPorSql(string consultaSql, params System.Data.SqlClient.SqlParameter[] parametros)
{
return contexto.Database.SqlQuery<t>(consultaSql, parametros).AsQueryable();
}
#endregion
}
}
</t></t></t></t></t></func></func></tkey></t></t></t></t></func></func></tkey></t></t></t></func></t></t></t></func></func></tkey></t></t></func></t></t></t></func></t></t></t></t>
Plantilla T4 generadora de clases de reposiotrio:
<#@ template language="C#" debug="false" hostspecific="true"#>
<#@ include file="EF.Utility.CS.ttinclude"#>
<#@ output extension=".cs"#>
<#
CodeGenerationTools codigo = new CodeGenerationTools(this);
MetadataLoader cargador = new MetadataLoader(this);
CodeRegion region = new CodeRegion(this, 1);
MetadataTools ef = new MetadataTools(this);
string archivoEntrada1 = @"R:\Proyectos\ArquitecturaTresCapas\Modelo\Modelo.edmx";
EdmItemCollection ColeccionElementos1 = cargador.CreateEdmItemCollection(archivoEntrada1);
string espacioNombres = codigo.VsNamespaceSuggestion();
EntityFrameworkTemplateFileManager gestorArchivos = EntityFrameworkTemplateFileManager.Create(this);
#>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ArquitecturaTresCapas.IDAL;
using ArquitecturaTresCapas.Modelo;
namespace ArquitecturaTresCapas.DAL
{
<#
foreach (EntityType entidad in ColeccionElementos1.GetItems<entitytype>().OrderBy(e => e.Nombre))
{
#>
public partial class <#=entidad.Nombre#>Repositorio : RepositorioBase<<#=entidad.Nombre#>>,I<#=entidad.Nombre#>Repositorio{ }
<#}#>
}
</entitytype>
Código generado:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ArquitecturaTresCapas.IDAL;
using ArquitecturaTresCapas.Modelo;
namespace ArquitecturaTresCapas.DAL
{
public partial class CompraRepositorio : RepositorioBase<compra>,ICompraRepositorio{ }
public partial class MenuRepositorio : RepositorioBase<menu>,IMenuRepositorio{ }
public partial class ProductoRepositorio : RepositorioBase<producto>,IProductoRepositorio{ }
public partial class RolRepositorio : RepositorioBase<rol>,IRolRepositorio{ }
public partial class RolMenuRepositorio : RepositorioBase<rolmenu>,IRolMenuRepositorio{ }
public partial class UsuarioRolRepositorio : RepositorioBase<usuariorol>,IUsuarioRolRepositorio{ }
public partial class UsuarioRepositorio : RepositorioBase<usuario>,IUsuarioRepositorio{ }
}
</usuario></usuariorol></rolmenu></rol></producto></menu></compra>
3: Interfaz de Lógica de Negocio (IBLL)
Interfaz base para la lógica de negocio:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
namespace ArquitecturaTresCapas.IBLL
{
public interface ILogicaNegocioBase<t> where T : class
{
int GuardarCambios();
void Agregar(T entidad);
void Eliminar(T entidad);
void EliminarPor(Expression<func bool="">> condicionEliminacion);
void Modificar(T entidad, params string[] nombresPropiedades);
IQueryable<t> Donde(Expression<func bool="">> expresionLambda);
IQueryable<t> DondeOrdenarPor<tkey>(Expression<func bool="">> expresionLambda, Expression<func tkey="">> selectorClave, bool ascendente = true);
IQueryable<t> DondeIncluir(Expression<func bool="">> expresionLambda, params string[] nombresPropiedadesIncluidas);
IQueryable<t> DondeIncluirOrdenarPor<tkey>(Expression<func bool="">> expresionLambda, Expression<func tkey="">> selectorClave, bool ascendente = true, params string[] nombresPropiedadesIncluidas);
IEnumerable<t> DondePaginar<tkey>(int indicePagina, int tamanoPagina, out int totalRegistros, Expression<func bool="">> expresionLambda, Expression<func tkey="">> selectorClave, bool ascendente = true, params string[] nombresPropiedadesIncluidas);
IQueryable<t> ConsultarPorSql(string consultaSql, params System.Data.SqlClient.SqlParameter[] parametros);
}
}
</t></func></func></tkey></t></func></func></tkey></t></func></t></func></func></tkey></t></func></t></func></t>
Plantilla T4 generadora de interfaces de lógica de negocio:
<#@ template language="C#" debug="false" hostspecific="true"#>
<#@ include file="EF.Utility.CS.ttinclude"#>
<#@ output extension=".cs"#>
<#
CodeGenerationTools codigo = new CodeGenerationTools(this);
MetadataLoader cargador = new MetadataLoader(this);
CodeRegion region = new CodeRegion(this, 1);
MetadataTools ef = new MetadataTools(this);
string archivoEntrada1 = @"R:\Proyectos\ArquitecturaTresCapas\Modelo\Modelo.edmx";
EdmItemCollection ColeccionElementos1 = cargador.CreateEdmItemCollection(archivoEntrada1);
string espacioNombres = codigo.VsNamespaceSuggestion();
EntityFrameworkTemplateFileManager gestorArchivos = EntityFrameworkTemplateFileManager.Create(this);
#>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ArquitecturaTresCapas.Modelo;
namespace ArquitecturaTresCapas.IBLL
{
<#
foreach (EntityType entidad in ColeccionElementos1.GetItems<entitytype>().OrderBy(e => e.Nombre))
{
#>
public partial interface I<#=entidad.Nombre#>LogicaNegocio : ILogicaNegocioBase<<#=entidad.Nombre#>>{ }
<#}#>
}
</entitytype>
Código generado:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ArquitecturaTresCapas.Modelo;
namespace ArquitecturaTresCapas.IBLL
{
public partial interface ICompraLogicaNegocio : ILogicaNegocioBase<compra>{ }
public partial interface IMenuLogicaNegocio : ILogicaNegocioBase<menu>{ }
public partial interface IProductoLogicaNegocio : ILogicaNegocioBase<producto>{ }
public partial interface IRolLogicaNegocio : ILogicaNegocioBase<rol>{ }
public partial interface IRolMenuLogicaNegocio : ILogicaNegocioBase<rolmenu>{ }
public partial interface IUsuarioRolLogicaNegocio : ILogicaNegocioBase<usuariorol>{ }
public partial interface IUsuarioLogicaNegocio : ILogicaNegocioBase<usuario>{ }
}
</usuario></usuariorol></rolmenu></rol></producto></menu></compra>
4: Lógica de Negocio (BLL)
Implementación base de la lógica de negocio:
using System;
using System.Collections.Generic;
using System.Linq;
namespace ArquitecturaTresCapas.BLL
{
using ArquitecturaTresCapas.IBLL;
using ArquitecturaTresCapas.IDAL;
using System.Data.SqlClient;
public partial class LogicaNegocioBase<t> : ILogicaNegocioBase<t> where T : class
{
protected IRepositorioBase<t> repositorioBase;
public void Agregar(T entidad)
{
repositorioBase.Agregar(entidad);
}
public void Eliminar(T entidad)
{
repositorioBase.Eliminar(entidad);
}
public void EliminarPor(Expression<func bool="">> condicionEliminacion)
{
repositorioBase.EliminarPor(condicionEliminacion);
}
public void Modificar(T entidad, params string[] nombresPropiedades)
{
repositorioBase.Modificar(entidad, nombresPropiedades);
}
public IQueryable<t> ConsultarPorSql(string consultaSql, SqlParameter[] parametros)
{
return repositorioBase.ConsultarPorSql(consultaSql, parametros);
}
public int GuardarCambios()
{
return repositorioBase.GuardarCambios();
}
public IQueryable<t> Donde(Expression<func bool="">> expresionLambda)
{
return repositorioBase.Donde(expresionLambda);
}
public IQueryable<t> DondeIncluir(Expression<func bool="">> expresionLambda, params string[] nombresPropiedadesIncluidas)
{
return repositorioBase.DondeIncluir(expresionLambda, nombresPropiedadesIncluidas);
}
public IQueryable<t> DondeIncluirOrdenarPor<tkey>(Expression<func bool="">> expresionLambda, Expression<func tkey="">> selectorClave, bool ascendente = true, params string[] nombresPropiedadesIncluidas)
{
return repositorioBase.DondeIncluirOrdenarPor<tkey>(expresionLambda, selectorClave, ascendente, nombresPropiedadesIncluidas);
}
public IQueryable<t> DondeOrdenarPor<tkey>(Expression<func bool="">> expresionLambda, Expression<func tkey="">> selectorClave, bool ascendente = true)
{
return repositorioBase.DondeOrdenarPor<tkey>(expresionLambda, selectorClave, ascendente);
}
public IEnumerable<t> DondePaginar<tkey>(int indicePagina, int tamanoPagina, out int totalRegistros, Expression<func bool="">> expresionLambda, Expression<func tkey="">> selectorClave, bool ascendente = true, params string[] nombresPropiedadesIncluidas)
{
return repositorioBase.DondePaginar<tkey>(indicePagina, tamanoPagina, out totalRegistros, expresionLambda, selectorClave, ascendente, nombresPropiedadesIncluidas);
}
}
}
</tkey></func></func></tkey></t></tkey></func></func></tkey></t></tkey></func></func></tkey></t></func></t></func></t></t></func></t></t></t>
Plantilla T4 generadora de clases de lógica de negocio:
<#@ template language="C#" debug="false" hostspecific="true"#>
<#@ include file="EF.Utility.CS.ttinclude"#>
<#@ output extension=".cs"#>
<#
CodeGenerationTools codigo = new CodeGenerationTools(this);
MetadataLoader cargador = new MetadataLoader(this);
CodeRegion region = new CodeRegion(this, 1);
MetadataTools ef = new MetadataTools(this);
string archivoEntrada1 = @"R:\Proyectos\ArquitecturaTresCapas\Modelo\Modelo.edmx";
EdmItemCollection ColeccionElementos1 = cargador.CreateEdmItemCollection(archivoEntrada1);
string espacioNombres = codigo.VsNamespaceSuggestion();
EntityFrameworkTemplateFileManager gestorArchivos = EntityFrameworkTemplateFileManager.Create(this);
#>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ArquitecturaTresCapas.Modelo;
using ArquitecturaTresCapas.IBLL;
using ArquitecturaTresCapas.IDAL;
namespace ArquitecturaTresCapas.BLL
{
<#
foreach (EntityType entidad in ColeccionElementos1.GetItems<entitytype>().OrderBy(e => e.Nombre))
{
#>
public partial class <#=entidad.Nombre#>LogicaNegocio : LogicaNegocioBase<<#=entidad.Nombre#>>, I<#=entidad.Nombre#>LogicaNegocio
{
I<#=entidad.Nombre#>Repositorio repositorio;
public <#=entidad.Nombre#>LogicaNegocio(I<#=entidad.Nombre#>Repositorio repositorio){
this.repositorio = repositorio;
this.repositorioBase = repositorio;
}
}
<#}#>
}
</entitytype>
Código generado:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ArquitecturaTresCapas.BLL
{
using ArquitecturaTresCapas.Modelo;
using ArquitecturaTresCapas.IBLL;
using ArquitecturaTresCapas.IDAL;
public partial class RolLogicaNegocio : LogicaNegocioBase<rol>, IRolLogicaNegocio
{
IRolRepositorio repositorio;
public RolLogicaNegocio(IRolRepositorio repositorio) {
this.repositorio = repositorio;
this.repositorioBase = repositorio;
}
}
</rol>
5: Configuración de AutoFac
Archivo de configuraicón de AutoFac:
using Autofac;
using Autofac.Integration.Mvc;
using System.Reflection;
namespace AplicacionWeb
{
public class ConfiguracionAutoFac
{
public static void Registrar()
{
var constructor = new ContainerBuilder();
Assembly ensamblajeControladores = Assembly.Load("AplicacionWeb");
constructor.RegisterControllers(ensamblajeControladores);
Assembly ensamblajeRepositorios = Assembly.Load("ArquitecturaTresCapas.DAL");
constructor.RegisterTypes(ensamblajeRepositorios.GetTypes()).AsImplementedInterfaces();
Assembly ensamblajeLogicaNegocio = Assembly.Load("ArquitecturaTresCapas.BLL");
constructor.RegisterTypes(ensamblajeLogicaNegocio.GetTypes()).AsImplementedInterfaces();
var contenedor = constructor.Build();
System.Web.Mvc.DependencyResolver.SetResolver(new AutofacDependencyResolver(contenedor));
}
}
}
Registro en Global.asax:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
ConfiguracionAutoFac.Registrar();
}
6: Consumo en la capa de presentación
Ejemplo de controlador que consume la lógica de negocio:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
namespace AplicacionWeb.Controladores
{
using ArquitecturaTresCapas.IBLL;
using ArquitecturaTresCapas.Modelo.VistasModelo;
using Comunes;
using ArquitecturaTresCapas.Modelo.Filtros;
using System.Threading.Tasks;
using ArquitecturaTresCapas.Modelo;
public class InicioController : Controller
{
private ICompraLogicaNegocio logicaCompras;
public InicioController(ICompraLogicaNegocio logicaCompras)
{
this.logicaCompras = logicaCompras;
}
// GET: Inicio
public ActionResult Index()
{
ViewBag.compra = logicaCompras.Donde(c => c.Id == 6).FirstOrDefault().CantidadProductos;
ViewBag.tiempo = "La hora actual es: " + DateTime.Now.ToString();
return View();
}
}
}