Entity Framework y Specification Pattern

Introducción

Hace ya unos cuantos dias que vengo dándole vueltas a la cabeza para escribir un post sobre especificaciones y como construirlas sobre la infraestructura de Entity Framework, aunque en realidad sería igual sobre cualquier elemento IQueryable, aunque con alguna nota de implementación. Pensando en esta entrada no sabía si comenzar con una explicación sobre este patrón o ceñirme directamente a una posible implementación,  puesto que, me parece magnifica la documentación sobre el mismo que Fowler y Evans tienen en el documento de referencia. Al final, y despues de darle muchas vueltas me quedaré entre medias puesto que creo que es necesario realizar una pequeña introducción, aunque aconsejo encarecidamente desde aquí leerse el documento anterior si nunca ha visto información acerca de este patrón.

Sintetizándolo, aunque sea demasiada síntesis, podríamos decir que el patrón espeficación trata de lograr una separación entre la sentencia que unos objetos deberían de cumplir y el objeto que realiza la selección. Por ejemplo una especificación podría describir “los clientes que pertenecen a una determinada situación geográfica” pero no saber nada acerca de como realizar dicha selección. En definitiva no se trata nada más y nada menos que agregar una responsabilidad desacoplada de los objetos de dominio que la usan.

Este patrón es muy escuchado y usado en arquitecturas basadas en modelos de dominio y puesto en práctica en muchas arquitecturas para definir “criterios” de selección. Basándonos en la definición formal de este patrón, mostrada en la Figura 1, podríamos ver a primeras que una implementación de este patrón trabajando con IQueryable no tendría mucho sentido.

 

Specification_UML

La razón principal de la afirmación anterior viene de la propia definición del patron, la cual implica trabajar con objetos directamente en memoria puesto que el método IsSatisfiedBy tomaría una instancia del objeto en el cual queremos comprobar si cumple un determinado criterio y devolver true o false según se cumpla o no, algo que por supuesto no deseamos por la sobrecarga que esto implicaría. Por todo esto podríamos modificar un poco nuestra definición de Specification para que en vez de devolver un booleano negando o afirmando el cumplimiento de una especificación determinada podríamos devolver una “expression” con el criterio a cumplir. En el siguiente fragmento de código tendríamos un esqueleto de nuestro contrato base con esta ligera modificación.

Profundizando

Llegados a este punto podríamos decir que ya tenemos la base y la idea de lo que queremos construir, ahora, solamente falta seguir las propias normas y guias de este patrón empezándonos a crear nuestras especificaciones directas o “hard coded specifications” y nuestras especificaciones compuestas, al estilo And, Or …

Según avanzas en esta aproximación uno se da cuenta de que tendrá que realizar un buen esfuerzo de trabajo con árboles de expresiones, algo en el que no todo el mundo está muy puesto, y a lo que se le tiene algo de miedo, del que uno se puede curar leyendo el excelente libro de mi amigo y colega Octavio 🙂

Mi primera intentona, y fallida a mi pesar, era similar a lo siguiente:

Os podreís imaginar que la especificacion OR era similar a esta, simplemente modificando Expression.AndAlso por Expression.Or. Todo funcionaba de maravilla en mis test contra mi mock de los ObjectSet de Entity Framework hasta que pasando las pruebas de integración me di cuenta que el QueryProvider de Entity Framework no soportaba el método Invoke, al contrario que un QueryProvider sobre objetos en memoria, y que por lo tanto esta forma no me servía :-(.

Aunque ahora mismo pondré la solución fijaros como, de una forma elegante, manteniendo el principio de separación de responsabilidades y dejando un concepto de negocio como es un tipo especial de búsqueda perfectamente explícito, se podrían declarar especificaciones como la siguiente

NOTA: Seguramente que alguna vez ha pensado como hacer consultas distintas en función de parámetros usando conjunciones o disjunciones de expressiones, pues esta es una posible solución.

 

Una posible solución para especificaciones And y OR

Os podreís imaginar que seguramente existe más de una aproximación para este tema y que yo probablemente me haya decantado por una aproximación algo dura, pero la verdad es que me parecía la más adecuada. Releyendo algún post sobre el tema me acorde de la serie que Matt Warren tenía sobre el tema y como hacía uso del patrón Visitor para evaluar las expresiones, ExpressionVisitor. Además, navegando, me encontré con un ejemplo aceptable que resolvía este tema en el blog de Colling Meek el cual fué la solución que adopte.

Dada la explicación, lo que necesitamos es la siguiente clase que nos haga una recomposición de las expressiones en vez de un InvocationExpression, esta clase de apoyo es la siguiente:

La definición completa por lo tanto de una especificación And queda como sigue:

¿Por dónde continuamos?

Dentro de la jerarquía de especificaciones que se propone en el documento de Eric y Fowler podemos encontrar desde la especificación Not hasta una base para LeafSpecifications que tendríamos que construir… es decir, un poquito más de curro para poder disfrutar…

 

Un resumen

La verdad espero que le encontréis utilidad a esta forma de implementar el patrón Specification, y por supuesto, si no lo conociais espero que os levante un poco la curiosidad y veais las bondades que este puede tener  dentro de vuestros desarrollos, por supuesto me encantaría ver vuestras opiniones al respecto y si realmente esta forma de encajar criterios es adecuado para vuestras soluciones…

 

Saludos

Unai Zorrilla

 

 

4 comentarios sobre “Entity Framework y Specification Pattern”

  1. Excelente post Unai!!

    Qué bueno que te sirviera de ayuda un post de Colin, es mi vecino al otro lado del pasillo en la oficina… Ya le he dado las gracias de tu parte. 😛

    Vendras al Summit?

    M.

  2. Joder Miguel, que casualidad tio!, dale las gracias y dile para lo que ha servido :-). Este año tengo curro y no puedo, tenga ya a la family bastante abandonada 🙁

    Unai

  3. Hola Unai, hace poco que estoy estudiando la guia de arquitectura de n-capas, y es un excelente libro, compre tu libro de Entity es espectacular me ayudado a entender mas la capa de infraestructura, y he seguido algunos de los tutoriales en c# que has hecho, y me parecen excelentes, muy claros, pues necesito de tu ayuda he estado mirando sobre el patron especificacion y sobre los arboles de expresion, y no he logrado entenderlos muy bien,
    trate de comprar el libro que recomiendas de c#3.0 y linq de octavio( pero al parecer no lo hay en pdf ya hice la consulta a Krasis, estoy esperando la respuesta ya que vivo en colombia entonces me queda complicado comprar el impreso) para comprender los arboles de expresiones, bueno aca va el favor me puedes explicar estos temas con un ejemplo si es posible con un video asi de claros como los que hiciste para los tutoriales de c#, seria estupendo hermano se lo agradeceria en el alma, pues no siendo mas me despido y quiero agradecerte por todo el conocimiento que das ya que ayuda mucho

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *