5.5.2 Agregando clases genéricas para validar y/o consultar información
Vamos a crear una clase genérica con los métodos comunes como son obtener todos los registros, obtener un registro por id, agregar, modificar y borrar un registro.
Como cada tabla puede tener diferentes validaciones para agregar, borrar o modificar vamos a agregar una interfaz que nos permita validar cada regla de forma individual. Por ejemplo, podemos tener:
Una regla para validar que el nombre de la categoría no se repita
Regla para validar que no se repita la clave de la categoría.
De esta forma podemos probar las reglas de forma individual para encontrar mas rápido algún error. Agregamos una interfaz IRegla en nuestra carpeta Core
Primero vamos a crear una interfaz llamada IAccesoDAO en nuestra carpeta Core, esta interfaz cual contiene los métodos comunes, el cual utiliza generics, en el cual se recibe un objeto como parámetro, este objeto será el nombre de la clase de la base de datos, por ejemplo Categoria, Producto.
Ahora cambiamos nuestra clase CategoriaDAO para que utilice nuestra clase AccesoDAO y para el método Agregar creamos 2 reglas:
Validar el nombre repetido
Validar clave repetida.
Agregamos una carpeta llamada Rules la cual contendrá todas las reglas para todas las tablas. Agregamos una carpeta para la tabla Categoría. Creamos 2 clases una para validar que la clave no se repita y otra para validar que el nombre no se repita.
Por defecto las consultas que se hacen a las bases de datos se regresan objetos que internamente llevan un control de los campos para al momento de realizar un SaveChanges se guarden los cambios a todos los objetos que se han cambiado. Para estas reglas solo necesitamos conocer si existe un registro no deseamos llevar el control de cambios. Esto se realiza agregando AsNoTracking() en nuestras consultas, de esta manera se le indica a Entity Framework que el objeto es de solo lectura por lo cual hace el proceso mas eficiente. Agrega un nuevo archivo con el nombre ReglaNombreUnico.cs.
ReglaNombreUnico.cs
usingCaducaRest.Core;usingCaducaRest.Models;usingCaducaRest.Resources;usingMicrosoft.EntityFrameworkCore;usingSystem;usingSystem.Linq;namespaceCaducaRest.Rules.Categoria;/// <summary>/// Valida que el nombre no se repita/// </summary>publicclassReglaNombreUnico:IRegla{privatestring nombre;privatereadonlyCaducaContext contexto;privatereadonlyLocService localizacion;privateint id; /// <summary> /// Mensaje de error /// </summary>publicCustomError customError { get; set; } /// <summary> /// Valida que una cateogría no se llame igual al agregar /// </summary> /// <paramname="nombre">Nombre de la categoría</param> /// <paramname="context">Objeto para la bd</param> /// <paramname="locService">Objeto para mensajes en varios /// idiomas</param>publicReglaNombreUnico(int id,string nombre,CaducaContext context,LocService locService) {this.nombre= nombre;this.contexto= context;this.localizacion= locService;this.id= id; } /// <summary> /// Permite validar que el nombre de una categoría no se /// repita al agregar /// </summary> /// <returns>True si no se repite la categoría</returns>publicboolEsCorrecto() {var registroRepetido =contexto.Categoria.AsNoTracking() .FirstOrDefault(c =>c.Nombre== nombre&&c.Id!= id);if (registroRepetido !=null) { customError =newCustomError(400,String.Format(this.localizacion .GetLocalizedHtmlString("Repeteaded"),"categoría","nombre"),"Nombre");returnfalse; }returntrue; }}
Agrega otra regla para que la clave no se repita.
ReglaClaveUnico.cs
usingCaducaRest.Core;usingCaducaRest.Models;usingCaducaRest.Resources;usingMicrosoft.EntityFrameworkCore;usingSystem;usingSystem.Linq;namespaceCaducaRest.Rules.Categoria;/// <summary>/// Permite validar que no se repita la clave de una categoría/// al agregar/// </summary>publicclassReglaClaveUnico:IRegla{privateint clave;privateint id;privatereadonlyCaducaContext contexto;privatereadonlyLocService localizacion; /// <summary> /// Mensaje de error /// </summary>publicCustomError customError { get; set; } /// <summary> /// Constructor para verificar que la clave no se repite /// en una categoría al agregar /// </summary> /// <paramname="clave">Clave de la categoría</param> /// <paramname="context">Objeto para la bd</param> /// <paramname="locService">Objeto para traducuir a varuis idiomas</param>publicReglaClaveUnico(int id,int clave,CaducaContext context,LocService locService) {this.clave= clave;this.contexto= context;this.localizacion= locService;this.id= id; } /// <summary> /// Indica si la clave de la categoría no se repite /// al agregar /// </summary> /// <returns></returns>publicboolEsCorrecto() {var registroRepetido =contexto.Categoria.AsNoTracking() .FirstOrDefault(c =>c.Clave== clave&&c.Id!= id);if (registroRepetido !=null) { customError =newCustomError(400,String.Format(this.localizacion.GetLocalizedHtmlString("Repeteaded"),"categoría","clave"),"Clave");returnfalse; }returntrue; }}
Modificamos nuestra clase CategoriaDAO agregando nuestra clase AccesoDAO pasando como parámetro la tabla Categoria, cambiamos el método AgregarAsync para crear una regla para validar que no este repetido el nombre y otra para que no este repetido la clave. Luego pasamos el arreglo de reglas a validar.
Esta forma es una alternativa para validar reglas personalizadas a cualquier objeto independiente al entity framework. Por ejemplo validaciones que se pueden hacer a un archivo de excel antes de importarlo. Puede parecer muchísimo más código pero nos permite validar de forma individual cada regla, lo cual lo hace más fácil de probar. También es mas claro saber las reglas que se siguen sin tener que leer muchas líneas de código.
El entity framework de .net ofrece una forma más sencilla de realizar validaciones personalizadas, esto lo veremos en la siguiente lección
Para practicar puedes cambiar el método Modificar y crear las reglas personalizadas para modificar y comparar con mi solución en github