14

Bueno, no estoy seguro de si ese es exactamente el título correcto, pero básicamente he tenido muchos problemas al usar repositorios en aplicaciones MVC de tal manera que puede sustituir un conjunto de repositorios, implementar una tecnología de almacenamiento de datos diferente, para otro.Usando el patrón de repositorio para soportar múltiples proveedores

Por ejemplo, supongamos que quiero utilizar Entity Framework para mi aplicación. Sin embargo, también quiero tener un conjunto de datos de prueba implementados en listas codificadas. Me gustaría tener un conjunto de interfaces (IUserRepository, IProductRepository, etc. - no hablemos de un IRepository más genérico <T> por ahora) que ambos enfoques pueden crear instancias. Luego, usando (digamos) una herramienta de inyección de dependencias como Ninject o Castle Windsor, puedo cambiar entre el proveedor de la entidad marco (accediendo a la base de datos real) y el proveedor de la prueba (accediendo a las listas).

En pocas palabras, aquí está el problema:

- Si se va a utilizar Entity Framework, desea que sus repositorios de regresar IQueryable <SomeType>.

- Si va a utilizar listas codificadas, NO quiere que sus repositorios devuelvan IQueryable, porque agrega mucho a la sobrecarga, y además, Linq to Entities es significativamente diferente de Linq to Objects, causando muchos dolores de cabeza en el código que es común para ambos proveedores.

En otras palabras, he encontrado que el mejor enfoque aísla todo el código dependiente de EF dentro de los repositorios, para que los repositorios devuelvan IEnumerable o IList o algo así - entonces tanto EF como otras tecnologías pueden usar el mismos repositorios. Por lo tanto, todas las IQueryable estarían contenidas DENTRO de los repositorios de EF. De esta forma, puede usar Linq para Entidades con los repositorios de EF, y Linq para Objetos con los repositorios de Prueba.

Sin embargo, este enfoque pone una enorme cantidad de la lógica de negocios en los repositorios, y resulta en código muy duplicado: la lógica debe duplicarse en cada uno de los repositorios, incluso si las implementaciones son algo diferentes.

Toda la idea de los repositorios como esta capa que es muy delgada y simplemente se conecta a la base de datos se pierde entonces; los repositorios son "depósitos" de lógica de negocios así como de conectividad de almacenamiento de datos. No puede simplemente tener Buscar, Guardar, Actualizar, etc.

No he podido resolver esta discrepancia entre la necesidad de aislar el código dependiente del proveedor y tener lógica comercial en una ubicación centralizada.

¿Alguna idea? Si alguien pudiera señalarme un ejemplo de implementación que aborde esta preocupación, le agradecería mucho. (He leído mucho, pero no puedo encontrar nada de lo que habla específicamente sobre estos temas.)

ACTUALIZACIÓN:

Creo que estoy empezando a sentir que no es probable que sea posible tener repositorios que pueden ser intercambiado por diferentes proveedores, por ejemplo, si va a utilizar Entity Framework, solo debe dedicar toda su aplicación a Entity Framework. Pruebas unitarias? Estoy luchando con eso. Mi práctica hasta ahora ha sido establecer un repositorio separado con datos codificados y usarlo para pruebas unitarias, así como probar la aplicación antes de configurar la base de datos. Creo que tendré que buscar una solución diferente, quizás alguna herramienta burlona.

Pero entonces surge la pregunta de por qué usar repositorios, y especialmente por qué usar interfaces de repositorio. Estoy trabajando en esto.Creo que determinar la mejor práctica va a llevar un poco de investigación.

+0

Otra publicación sobre IQueryable: http: // stackoverflow.com/questions/718624/to-return-iqueryablet-or-not-return-iqueryablet – aqwert

+0

En pocas palabras, resume el estado en el que creo que todos se encuentran y las preguntas que tienen en algún momento a lo largo de la línea al aprender .net/mvc/ef/patrones de diseño. Preguntas y respuestas útiles –

Respuesta

14

¿Qué puedo decir? Bienvenido al club ...

Lo que encontraste es un problema al que llegaron muchos desarrolladores que siguieron el "auge del repositorio" con EFv4. Sí, es el problema y el problema es realmente complejo. He hablado de ello varias veces:

tema aparte es la razón por utilizar repositorios:

Básicamente su camino propuesto es una solución, pero ¿realmente lo quieres? En mi opinión, el resultado no es un repositorio, sino que el Objeto de acceso a datos (DAO) expone muchos métodos de acceso. definición Repositorio por Martin Fowler es:

Un repositorio media entre las capas de dominio y de asignación de datos, actuando como un objeto de dominio colección en memoria. Los objetos del cliente construyen especificaciones de consulta declarativamente y los presentan al Repositorio para satisfacción con . Los objetos pueden ser añadidos a y se retiran del repositorio, como que pueden partir de 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. Conceptualmente, un Repositorio encapsula el conjunto de objetos persistidos en un almacén de datos y las operaciones realizadas sobre ellos, proporcionando una vista más orientada a objetos de la capa de persistencia. El repositorio también admite el objetivo de logrando una separación limpia y dependencia unidireccional entre el dominio y las capas de mapeo de datos.

Creo que la exposición de IQueryable cumple esta 100 veces mejor que la creación de una interfaz pública similar a los depósitos de la era de procedimientos almacenados - un método de acceso por procedimiento almacenado (consulta fija).

El problema se puede resumir en la regla de leaky abstraction. IQueryable es una abstracción de la consulta de la base de datos, pero las características proporcionadas por IQueryable dependen del proveedor. Proveedor diferente = conjunto de características diferentes.

¿Qué es una conclusión? ¿Deseas tal arquitectura debido a las pruebas? En tal caso, comience a usar las pruebas de integración como se propuso en las primeras dos respuestas vinculadas porque, en mi opinión, es la forma menos dolorosa. Si sigue el enfoque propuesto, debe seguir utilizando las pruebas de integración para verificar que los repositorios oculten todas las consultas y la lógica relacionadas con EF.

+0

Guau, ¡mucho que leer! Permítanme reflexionar sobre todo, y me pondré en contacto con usted mañana. – Cynthia

+0

Soy parte de tus ejemplos. Tengo un problema con una de sus afirmaciones: "La primera razón es algún tipo de pureza arquitectónica y gran idea de que si usted hace que sus capas superiores sean independientes de EF, más adelante podrá cambiar a otro marco de persistencia. ¿Cuántas veces lo vio? cosa en el mundo real? " De hecho, tuve que hacer esto hace un par de años, mi primer proyecto de MVC. Estaba usando código de EF primero, pero me di cuenta a mitad de camino que no sería RTM antes de que lo necesitara, así que tuve que cambiar a conjuntos de datos fuertemente tipados bajo presión de tiempo. (continúa ...) – Cynthia

+0

Tuve que crear un nuevo repositorio, y tuve que cambiar todas las interfaces del repositorio con prisa para devolver IEnumerable en lugar de IQueryable, y juré que nunca más me quedaría así. Tal vez sea un problema menor ahora que EF 4.1 está fuera, pero esa experiencia está grabada en mi cerebro. Realmente no me gusta la idea de que los repositorios dependan de una tecnología específica, aunque entiendo tu punto. Más tarde ... – Cynthia

Cuestiones relacionadas