Hay veces en que necesitamos buscar dentro de un listado genérico de objetos los que cumplan con determinada condición. Como nos tiene acostumbrados (y por suerte) .NET usamos LINQ y como parámetros expresiones Lambda, la verdad que esta forma nos facilita y ahorra mucho trabajo pero por sobre todo el código queda super elegante.
El problema: Que pasa cuando dejamos en una aplicacion que el usuario sea quien decide la forma de filtrar los datos o tenemos algun input de datos que da como resultado que nuestra busqueda sea dinamica y no estatica (por ejemplo la expresion lambda har codeada en el fuente (e => e.Id == num)) ?
Ejemplo tenemos un formulario WinForm con los distintos filtros y vemos como quedaria el codigo todavia con el problema de no ser la consulta dinamica. Lo que vamos a buscar son atumoviles asi que tenemos la clase Automovil.
Como vemos ya estamos en un problema no podemos buscar por varios criterios de esa forma.
Solución: vamos a utilizar el Patron Specification de Martin Fowler , pero usando las ventajas y utilizando C Sharp (en este caso , pero saben que es lo mismo para VB.NET) o sea que el patron esta modificado no es su version original (JAVA). Este patrón nos permitirá hacer búsquedas dinámicas según los criterios que se seleccionen de una forma muy elegante y código altamente reutilizable.
Para comenzar vamos a desarrollar el contrato de las especificaciones y una clase abstracta de la cual van a heredar las demas como Expresion , And , Or y Not.
Expression: esta clase tiene una variable de instancia del tipo Func<t, bool> (delegado) que sera el encargado de testear si el objeto por el que consultemos cumple con el criterio, la prueba se realiza dentro del metodo IsSatisfiedBy que sera sobrecargado por ser abstracto (implementacion obligatoria).
Entonces hasta aca tenemos una clase que tiene un metodo que invoca el delegado pasado por constructor y testeara si el objeto cumple con el criterio establecido.
Para los que no conocen Func<t, bool> sifnifica que es una expresion o llamesmole un metodo que recibe un parametro del tipo t (generico) y retorna bool.
Ahora crearemos las especificaciones And , Or y NOT.
Ya tenemos las clases que representan las especificaciones condicionales , explico brevemente (siempre es mejor debuggear el coduigo y ver como funciona) por ejemplo And hereda de BaseSpecification , para crear una instancia se deben pasar por constructor dos especificaciones que representan el lado izquierdo y el lado derecho de toda condicion "Y" logica, esto se evalua en el metodo sobrecargado IsSatisfiedBy. Siguiendo con Or que es casi igual solo que IsSatisfiedBy pregunta si se cumple una o la otra , y por ultimo tenemos a Not que seria una especificación negada.
Medio quilombo al principio pero vamos a testear ahora antes de mostrar mas trucos (;-)).
Como habia mencionado tenemos la clase Automovil con algunas propiedades y un listado de automoviles , ahora le vamos a tirar unas consultas con linq y vemos los resultados.
Ejecutamos el test. .... donde el Id del Automovil sea igual a 3.
Por ahora mas que bien que bien , nuestra especificación cumplio su cometido y conseguimos el automóvil que necesitábamos dentro de la colección.
Ahora vamos a combinar especificaciones, asi que usaremos And , Or y Not. Para combinar usaremos metodos de extension, estos metodos extienden a ISpecification y nos devuelven una And (metodo And) o una Or (metodo Or).
Vamos a verlo por que resulta confuso al pricipio.
Excelente !!! Tenemos exactamente lo que buscamos combinando las expresiones , ahora volvamos al caso del win form para generar nuestra consulta dinamica y cargar la grilla con lo que buscamos (Ejemplo minimalista me paso de cargar el combo con las marcas).
Perfecto dio resultado , trajo justo lo que queremos, el listado de automoviles esta en la clase ExampleHerlper para comprobar que todo salio bien.
Terminando ......... como se puede apreciar las consultas sobre LINQ quedan dianmicas por los criterios que necesitamos y un codigo totalmente elegante. Reconozco que el nombre de las clases es medio largo pero lo deje asi para que sea bien explicito el ejemplo.
Dejo que lo prueben mas ustedes , y combinen todas las especificaciones que se les ocurra.
Mas adelante voy a mostrar como hacer esto pero contra repositorios de Entity Framework.
Dejame tu comentario !!!!!!!
Descargate el ejemplo de mi dropbox
Descargate el ejemplo por Mega
Christian DC.








Muy interesante me sera de mucha ayuda, muchs gracias
ResponderEliminarExcelente trabajo, muy bueno.
ResponderEliminar