entity framework - unit - ¿Qué problema específico resuelve el patrón de repositorio?
patrón repositorio entity framework (7)
Creo que comúnmente se piensa en el término "repositorio" en la forma en que el " patrón de repositorio " se describe en el libro Patterns of Enterprise Application Architecture de Martin Fowler.
Un repositorio media entre el dominio y las capas de mapeo de datos, actuando como una colección de objetos de dominio en memoria. Los objetos del cliente construyen especificaciones de consulta de forma declarativa y las envían al repositorio para su satisfacción. Los objetos se pueden agregar y eliminar del Repositorio, como pueden hacerlo desde una simple colección de objetos, y el código de mapeo encapsulado por el Repositorio llevará a cabo las operaciones apropiadas detrás de las escenas.
En la superficie, Entity Framework logra todo esto, y se puede usar como una forma simple de un repositorio. Sin embargo, puede haber más en un repositorio que simplemente una abstracción de capa de datos.
Según el libro Domain Driven Design de Eric Evans, un repositorio tiene estas ventajas:
- Presentan a los clientes un modelo simple para obtener objetos de persistencia y administrar su ciclo de vida
- Desacoplan el diseño de aplicaciones y dominios de la tecnología de persistencia, estrategias de bases de datos múltiples o incluso múltiples fuentes de datos
- Comunican las decisiones de diseño sobre el acceso a objetos
- Permiten la sustitución fácil de una implementación ficticia, para la prueba unitaria (por lo general, utilizando una colección en memoria).
El primer punto equivale aproximadamente al párrafo anterior, y es fácil ver que Entity Framework mismo lo logra fácilmente.
Algunos argumentarían que EF logra el segundo punto también. Pero comúnmente EF se usa simplemente para convertir cada tabla de base de datos en una entidad EF y pasarla a la IU. Puede estar abstrayendo el mecanismo de acceso a los datos, pero apenas está abstrayendo la estructura de datos relacionales detrás de las escenas.
En aplicaciones más simples que en su mayoría están orientadas a datos , este podría no parecer un punto importante. Pero a medida que las reglas de dominio / lógica de negocios de las aplicaciones se vuelven más complejas, es posible que desee estar más orientado a objetos . No es raro que la estructura relacional de los datos contenga idiosincrasias que no son importantes para el dominio comercial, sino que son efectos secundarios del almacenamiento de datos. En tales casos, no es suficiente abstraer el mecanismo de persistencia sino también la naturaleza de la estructura de datos en sí misma. Por sí solo, EF no te ayudará a hacer eso, pero sí lo hará una capa de repositorio.
En cuanto a la tercera ventaja, EF no hará nada (desde una perspectiva DDD) para ayudar. Normalmente, DDD utiliza el repositorio no solo para abstraer el mecanismo de persistencia de datos, sino también para proporcionar restricciones sobre cómo se puede acceder a ciertos datos:
Tampoco necesitamos acceso de consulta para objetos persistentes que sean más convenientes de encontrar por recorrido. Por ejemplo, la dirección de una persona se puede solicitar desde el objeto Persona. Y lo más importante, cualquier objeto interno a un AGREGADO tiene prohibido el acceso, excepto al atravesarlo desde la raíz.
En otras palabras, no tendría un ''AddressRepository'' solo porque tiene una tabla de direcciones en su base de datos. Si su diseño elige administrar cómo se accede a los objetos de Dirección de esta manera, PersonRepository es donde definiría e impondría la elección de diseño.
Además, un repositorio DDD normalmente sería donde se encapsulan ciertos conceptos comerciales relacionados con conjuntos de datos de dominio. Un OrderRepository puede tener un método llamado OutstandingOrdersForAccount que devuelve un subconjunto específico de Pedidos. O un repositorio de Cliente puede contener un método PreferredCustomerByPostalCode.
Las clases DataContext de Entity Framework no se prestan bien a dicha funcionalidad sin la capa de abstracción de repositorio agregada. Funcionan bien para lo que DDD llama Especificaciones, que pueden ser expresiones booleanas simples enviadas a un método simple que evaluará los datos contra la expresión y devolverá una coincidencia.
En cuanto a la cuarta ventaja, aunque estoy seguro de que hay ciertas estrategias que podrían permitirle a uno sustituir el contexto de datos, envolverlo en un repositorio lo hace completamente simple.
Con respecto a la ''Unidad de trabajo'', esto es lo que el libro de DDD tiene que decir:
Deje el control de la transacción al cliente. Aunque el REPOSITORY se insertará y eliminará de la base de datos, normalmente no comprometerá nada. Por ejemplo, es tentador comprometerse después de guardar, pero presumiblemente el cliente tiene el contexto para iniciar y confirmar correctamente las unidades de trabajo. La gestión de transacciones será más simple si el REPOSITORIO no se ocupa.
(Nota: Mi pregunta tiene preocupaciones muy similares a las de la persona que hizo esta pregunta hace tres meses, pero nunca fue respondida).
Recientemente comencé a trabajar con MVC3 + Entity Framework y sigo leyendo que la mejor práctica es usar el patrón de repositorio para centralizar el acceso al DAL. Esto también se acompaña con explicaciones de que desea mantener el DAL separado del dominio y especialmente de la capa de vista. Pero en los ejemplos que he visto, el repositorio es (o parece estar ) simplemente devolviendo entidades DAL, es decir, en mi caso el repositorio devolvería entidades EF.
Entonces mi pregunta es, ¿de qué sirve el repositorio si solo devuelve entidades DAL? ¿Esto no agrega una capa de complejidad que no elimina el problema de pasar entidades DAL entre capas? Si el patrón de repositorio crea un "único punto de entrada en el DAL", ¿cómo es eso diferente del objeto de contexto? Si el repositorio proporciona un mecanismo para recuperar y persistir objetos DAL, ¿cómo es eso diferente del objeto de contexto?
Además, leí en al menos un lugar que el patrón de unidad de trabajo centraliza el acceso al repositorio para administrar el objeto (s) de contexto de datos, pero no entiendo por qué esto es importante tampoco.
Estoy 98.8% seguro de que me estoy perdiendo algo aquí, pero por mis lecturas no lo vi. Por supuesto, puede que no esté leyendo las fuentes correctas ...: /
Creo que hay una gran incomprensión de lo que muchos artículos llaman "repositorio". Y es por eso que hay dudas sobre qué valor real aportan esas abstracciones.
En mi opinión, el repositorio en su forma pura es IEnumerable, mientras que usted y muchos artículos están hablando de "servicio de acceso a datos".
He escrito sobre esto here .
Dado su escenario, simplemente optaría por un conjunto de interfaces que representan qué estructuras de datos (sus Modelos de dominio) necesitan ser devueltos desde su capa de datos. Su implementación puede ser una mezcla de EF, Raw ADO.Net o cualquier otro tipo de Data Store / Provider. La estrategia clave aquí es que la implementación se abstraiga del consumidor inmediato: su capa de Dominio. Esto es útil cuando quiere probar sus objetos de dominio y, en situaciones menos comunes, cambie su plataforma de proveedor de datos / base de datos por completo.
Si ya no lo ha hecho, debería considerar el uso de un contenedor IOC ya que facilitan el acoplamiento de su solución mediante la Inyección de Dependencia . Hay muchos disponibles , personalmente prefiero Ninject .
La capa de dominio debe encapsular toda su lógica comercial: las reglas y los requisitos del dominio problemático, y puede ser consumida directamente por su aplicación web MVC3. En ciertas situaciones, tiene sentido introducir una capa de servicios que se ubica sobre la capa de dominio, pero esto no siempre es necesario y puede ser excesivo para aplicaciones web sencillas.
Otra cosa a tener en cuenta es que incluso cuando sepa que trabajará con un único almacén de datos, podría tener sentido crear una abstracción del repositorio. La razón es que puede haber una función que su aplicación necesite para que su ORM du jour funcione mal (rendimiento), para nada, o simplemente no sepa cómo hacer que el ORM se adapte a sus necesidades.
Si está ajustando su ORM detrás de una interfaz de repositorio bien pensada, puede cambiar fácilmente entre diferentes tecnologías como mejor le parezca. No es raro en mis repositorios ver que algunos métodos usan EF para su trabajo y otros que usan algo como PetaPoco, o (gasp) el código ADO.net. La abstracción del repositorio le permite utilizar exactamente la herramienta correcta para el trabajo en cuestión sin filtrar estas complejidades en el código del cliente.
Sería útil en situaciones en las que tenga múltiples fuentes de datos y desee acceder a ellas utilizando una estrategia de codificación consistente.
Por ejemplo, puede tener múltiples modelos de datos de EF y algunos datos a los que se accede utilizando ADO.NET tradicional con procs almacenados, y algunos datos accedidos utilizando una API de terceros, y algunos accedidos desde una base de datos Access que vive en un servidor Windows NT4 manto de polvo en el armario de tu escoba.
Puede que no desee que su empresa o las capas de front-end se preocupen por el origen de los datos, de modo que construya un patrón de repositorio genérico para acceder a "datos", en lugar de acceder a "datos de Entity Framework".
En este escenario, las implementaciones de repositorio reales serán diferentes entre sí, pero el código que las llama no sabrá la diferencia.
Tienes razón, en esos casos simples, el repositorio es solo otro nombre para un DAO y trae solo un valor: el hecho de que puedes cambiar EF a otra técnica de acceso a datos. Hoy estás usando MSSQL, mañana querrás un almacenamiento en la nube. O utilizando un microorma en lugar de EF o cambiando de MSSQL a MySql.
En todos esos casos, es bueno que use un repositorio, ya que al resto de la aplicación no le importará qué almacenamiento está utilizando ahora.
También existe un caso limitado en el que se obtiene información de múltiples fuentes (sistema de archivos db +), un repositorio actuará como fachada, pero sigue siendo otro nombre para un DAO.
Un repositorio "real" es válido solo cuando se trata de objetos de dominio / negocios, para aplicaciones centradas en datos que no cambian el almacenamiento, solo el ORM es suficiente.
El DbContext
Entity Framework básicamente se asemeja a un repositorio (y una unidad de trabajo también). No necesariamente tiene que abstraerlo en escenarios simples.
La principal ventaja del repositorio es que su dominio puede ser ignorante e independiente del mecanismo de persistencia. En una arquitectura basada en capas, las dependencias apuntan desde la capa de interfaz de usuario hacia abajo a través del dominio (o generalmente llamada capa de lógica de negocios) a la capa de acceso a datos. Esto significa que la IU depende del BLL, que a su vez depende del DAL.
En una arquitectura más moderna (como propagada por el diseño impulsado por el dominio y otros enfoques orientados a objetos), el dominio no debería tener dependencias que señalen hacia afuera. Esto significa que la IU, el mecanismo de persistencia y todo lo demás deberían depender del dominio, y no al revés.
Un repositorio se representará a través de su interfaz dentro del dominio pero tendrá su implementación concreta fuera del dominio, en el módulo de persistencia. De esta forma, el dominio solo depende de la interfaz abstracta, no de la implementación concreta.
Básicamente se trata de orientación a objetos versus programación de procedimientos a nivel arquitectónico.
Ver también los Puertos y Adaptadores también conocidos como Arquitectura Hexagonal .
Otra ventaja del repositorio es que puede crear mecanismos de acceso similares a varias fuentes de datos. No solo para bases de datos, sino para tiendas basadas en la nube, API externas, aplicaciones de terceros, etc.