Repositorio Genérico Con EF 4.1 cuál es el punto

145

A medida que profundizo en el DbContext, DbSet y las interfaces asociadas, me pregunto por qué necesitaría implementar un repositorio "genérico" separado alrededor de estas implementaciones.

Parece que DbContext e IDbSet hacen todo lo que necesita e incluyen la "Unidad de trabajo" dentro de DbContext.

¿Me estoy perdiendo algo aquí o parece que a la gente le gusta agregar otra capa de dependencia sin ninguna razón?

Code Jammr
fuente
Este es un tema poco disputado / basado en la opinión. He discutido esto aquí .
Amit Joshi

Respuestas:

202

En realidad tienes razón. DbContextes una implementación del patrón de unidad de trabajo y IDbSetes una implementación del patrón de repositorio.

Los repositorios son actualmente muy populares y utilizados en exceso. Todos los usan solo porque hay docenas de artículos sobre la creación de repositorios para el marco de la entidad, pero en realidad nadie describe los desafíos relacionados con esta decisión.

Las razones principales para usar el repositorio son generalmente:

  • Ocultar EF de la capa superior
  • Hacer el código mejor comprobable

La primera razón es algún tipo de pureza arquitectónica y una gran idea de que si hace que sus capas superiores sean independientes de EF, más adelante puede cambiar a otro marco de persistencia. ¿Cuántas veces viste algo así en el mundo real? Esta razón hace que trabajar con EF sea mucho más difícil porque su repositorio debe exponer muchas características adicionales que envuelven lo que EF permite por defecto.

Al mismo tiempo, envolver el código EF puede mantener su código mejor organizado y siguiendo la regla de separación de preocupaciones. Para mí, esta puede ser la única ventaja real del repositorio y la unidad de trabajo, pero debe comprender que seguir esta regla con EF hará que su código sea más fácil de mantener y de leer, pero en el esfuerzo inicial para crear su aplicación será mucho mayor y para aplicaciones más pequeñas esto puede ser una complejidad innecesaria.

La segunda razón es parcialmente correcta. La gran desventaja de EF es la arquitectura rígida que apenas se puede burlar, por lo que si desea probar la capa superior de la unidad, debe envolver EF de alguna manera para permitir burlarse de su implementación. Pero esto tiene muchas otras consecuencias que describí aquí .

Yo sigo el blog de Ayende . Si alguna vez usó NHibernate, probablemente conozca sus artículos. Este chico recientemente escribió varios artículos en contra del uso del repositorio con NHibernate, pero NHibernate es mucho mejor para burlarse.

Ladislav Mrnka
fuente
3
Puede simular IDbSetque también puede definir una interfaz personalizada en su contexto derivado, pero eso es todo. Una vez que su código use ChangeTracker, Entradas o cualquier otra cosa, requerirá un gran esfuerzo para envolverlos a todos.
Ladislav Mrnka
1
Sí, EF no es una herramienta muy orientada al rendimiento. Al menos MS tiene muchas oportunidades para mejorar esto en futuras versiones.
Ladislav Mrnka
2
@chiccodoro: Correcto. Pero una vez que su clase simulada se expone IQueryableo acepta Expression<>como parámetro que se coloca internamente en la consulta Linq a entidades, está definiendo la lógica fuera del componente simulado con efectos secundarios que no se pueden probar con pruebas unitarias.
Ladislav Mrnka
8
Si estoy usando DbSet y BdContext directamente en mi capa empresarial, tengo que hacer referencia a EntityFramework.dll allí, así como en mi proyecto DataLayer. Eso solo me dice que necesita algún tipo de envoltura.
Ingó Vals
2
voto negativo: incompleto: abstraer EF detrás de una interfaz de repositorio puede hacer que se ejecute exactamente el mismo código de cliente tanto en SL como en WPF.
h.alex
21

Estoy luchando con los mismos problemas, y la simulación para la prueba unitaria de las capas EF es importante. Pero me encontré con este gran artículo que explica cómo configurar el EF 4.1 DbContext para que se pueda simular asegurándose de que su DbContext derivado implemente una interfaz genérica y exponga IDbSet en lugar de DbSet. Como estoy usando un enfoque de Base de datos primero, debido a que nuestra base de datos ya existe, simplemente modifiqué las plantillas T4 utilizadas para generar mi DbContext derivado para generar que devuelva interfaces IDbSet, así como derivar de mi interfaz genérica. De esa manera, todo se puede burlar fácilmente, y no necesita implementar su propia Unidad de trabajo o patrón de repositorio. Simplemente escriba su código de servicio para consumir su interfaz genérica, y cuando vaya a la unidad, pruébelo,

http://refactorthis.wordpress.com/2011/05/31/mock-faking-dbcontext-in-entity-framework-4-1-with-a-generic-repository/

Kendall Bennett
fuente
5

Una razón para crear el repositorio es para que pueda ocultar la implementación de DBSet y DbContext si decide pasar de EntityFramework a otra cosa o viceversa.

Por ejemplo, estaba usando NHibernate y envolví todas las llamadas a ese marco dentro de mis clases de repositorio. Devuelven IEnumerable para que sean "genéricos" y mis repositorios tienen las operaciones CRUD estándar (actualizar, eliminar, etc.). Hace mucho tiempo que me mudé a Entity Framework. Al hacerlo, no necesitaba cambiar nada en mis clases de ViewModel o más allá porque señalaban a mi repositorio; solo necesitaba cambiar el interior de mi repositorio. Esto hizo la vida mucho más fácil al migrar.

(Utilicé NHibernate porque nos estamos conectando a ISeries, y en ese momento, no había implementaciones rentables que usaran EF con ISeries. El único disponible era pagar $ 12,000 a IBM por su DB2Connect)

Leniel Maccaferri
fuente
"Casi" (sobre el tema de ocultar DBSet y DbContext) encontrará que no necesita exponer EF a ningún consumidor (por ejemplo, si aprovecha DI) pero necesita una interfaz que exponga las propiedades IDbSet <T> o vaya un paso más allá y escriba todas sus propiedades como IQueryable <T>, pero mi punto es que puede ocultar completamente su dependencia de DbSet y DbContext. Las operaciones CRUD se pueden escribir como métodos de extensión, puede escribir varios métodos de extensión para diferentes almacenes de respaldo. Sin embargo, no estaría ocultando el uso de LINQ.
Shaun Wilson