2011-10-29 15 views
24

Estoy comenzando un nuevo proyecto web utilizando ASP.NET Webforms + EF4. Estoy tratando de aplicar un patrón de repositorio con un patrón de unidad de trabajo siguiendo este tutorial: http://www.dotnetage.com/publishing/home/2011/07/05/6883/the-repository-pattern-with-ef-code-first-dependeny-injection-in-asp-net-mvc3.html¿La unidad de trabajo y los patrones de repositorio son muy útiles para grandes proyectos?

Creo que tengo la idea, pero mi pregunta es que cuando creo un objeto nuevo en el modelo, también tengo para definir ese objeto en IDALContext de la unidad de trabajo? ¿No es eso una ruptura para un desarrollo rápido? Además, si trabajas con múltiples desarrolladores y si no quieres que otros desarrolladores vean tu DAL, ¿cómo puedes gestionar esto? Porque en este patrón, como entiendo, cuando crea un nuevo objeto en el modelo, también debe definirlo en el contexto IDAL para este tutorial. Lo siento, estoy tan confundido por esto.

+1

La implementación mencionada de una unidad de trabajo es una porquería. ¡En mi opinión, la unidad de trabajo no debería saber nada sobre repositorios! Tener que definir cada entidad en IDALContext es realmente malo también :(Con NHibernate no tienes que hacer esas cosas. En general, la unidad de trabajo y el patrón de repositorio es útil para grandes proyectos. Acabas de leer un blog realmente malo post. Trate de encontrar otras soluciones. – Rookian

+0

@Rookian ¿Cómo lo aborda con NHibernate? ¿Utiliza un patrón UoW/Repository o simplemente DAOs? – Juri

+0

@Juri Uso Uow + Repositories. Para la implementación, eche un vistazo al http://codecampserver.codeplex.com/ – Rookian

Respuesta

18

Martin Fowler describe el papel del repositorio como: "Un repositorio media entre el dominio y las capas de mapeo de datos, actuando como una colección de objetos de dominio en memoria". Lo que Entity Framework 4.1 expone es un repositorio en ese sentido. Además, EF tiene una unidad de trabajo integrada. Por lo tanto, mi consejo es ignorar el artículo del blog que mencionaste en tu pregunta.

Este tipo de código no solo es inútil o inútil, ¡sino peligroso porque no se ha añadido ningún beneficio a su código, sino una dependencia!

public interface IUnitOfWork:IDisposable 
{ 
    int SaveChanges(); 
} 

public interface IDALContext : IUnitOfWork 
{ 
    ICategoryRepository Categories { get; } 
    IProductRepository Products { get; } 
} 

Para responder a su pregunta con una abstracción que media entre las capas de dominio y de asignación de datos, actuando como una colección de objetos de dominio en memoria es una necesidad para los proyectos "grandes". Y tener un mecanismo UnitOfWork bajo el capó puede ayudar a desacoplar su lógica de negocio del acceso a una cierta abstracción de acceso a datos.

TL; TR; Repository y UnitOfWork pueden ayudarlo, pero no lo aplique como en la publicación del blog.

+5

+1 para señalar que el contexto EF es a la vez un repositorio y una unidad de trabajo. Una clave para comprender los patrones es poder identificarlos en el código, incluso si no hay una clase llamada como el patrón. –

+0

¿Hay alguna manera de no definir cada repositorio en el IDALContext? El IDALContext está abarrotando cuando se necesitan más y más repositorios. En mi opinión, el IDALContext inte rface está violando uno de los principios SÓLIDOS, a saber, el "Principio de segregación de la interfaz". – Rookian

+0

Sí, hay una manera: simplemente no lo use. Puede usar el mismo DbContext por ejemplo en un alcance de solicitud HTTP para asegurarse de que su unidad de trabajo está haciendo lo que esperaba. – saintedlama

92

Ahora, la primera pregunta debería ser, ¿por qué necesito un repositorio o patrón de unidad de trabajo? ¿No podría simplemente usar el contexto EF del controlador, teniendo todo el poder de escribir directamente la consulta que necesito y devolver los datos?
Respuesta: Podría, pero la verdadera intención detrás es la capacidad de prueba y por lo tanto una mayor calidad, un código más fácil de mantener. Si separa su acceso a los datos y lo concentra en un solo lugar, puede simularlo durante las pruebas. Esto le permite unidad probar la lógica definida dentro de su controlador sin escribir efectivamente en un almacén de datos.

Antes de comenzar con la Unidad de trabajo, solo use echar un vistazo al Repository pattern. Esto básicamente abstrae el acceso a datos para una entidad dada. Entonces usted define métodos como Filter(), All(), Update (...), Insert (...), Delete (...) y finalmente, Save(). En realidad, la mayoría de estos podrían resumirse bastante fácilmente en una clase BaseRepository<TEntity>, de modo que al final solo tendrías que crear un nuevo repositorio en casos excepcionales con un comportamiento especial. De lo contrario, sería algo así como BaseRepository<Person> personRepo = new BaseRepository<Person>() o BaseRepository<Address> addressRepo = new BaseRepository<Address>() etc.

¿Por qué es necesaria la Unidad de trabajo?
Una unidad de trabajo representa todas las operaciones realizadas durante un cierto ciclo, en un entorno web normalmente por solicitud de HTTP. Esto significa que cuando ingresa una nueva solicitud, crea una nueva Unidad de trabajo, agrega cosas nuevas, la actualiza o la elimina y luego "compromete" los cambios invocando .save() o .commit() ..whatever. En realidad, si observa de cerca el Entity Framework DbContext (u ObjectContext), ya están representando algún tipo de Unidad de trabajo.
Sin embargo, si desea abstraerlo más, porque no necesariamente le gustaría tener su contexto EF en sus clases de controlador (recuerde: capacidad de prueba), entonces crea un UoW para agrupar sus Repositorios y también para asegurar que todos compartan el misma instancia de contexto EF. Puede lograr lo último también a través de un contenedor DI (contenedor de Inyección de Dependencia).

A sus preguntas: ¿Es útil en proyectos grandes?:
Definitivamente, especialmente en grandes proyectos. Se trata de mantener las responsabilidades separadas (acceso a los datos, lógica de negocios, lógica de dominio) y, por lo tanto, hacer que las cosas sean comprobables.

+1

esta es una publicación muy útil. gracias por la super explicación! – bas

+0

¿Necesita este tipo de transacciones con CQRS y consistencia final? – inf3rno

+1

@ inf3rno No estoy seguro sobre la relación con "consistencia eventual". Esto es completamente un patrón estructural. Por lo tanto, "podría" también aplicarlo a CQRS al tener dos UoW diferentes para la parte de Query y Command. Para ser honesto, nunca lo usé de esa manera. En mi humilde opinión, la parte importante aquí es saber que esto es para estructurar su aplicación, para mejorar su diseño-> comprobabilidad-> mantenibilidad. Si está en su camino o hace que su situación sea más compleja, simplemente no la use :) – Juri

1

Los patrones de diseño de software están diseñados para resolver problemas específicos con el contexto correcto, y si se utilizan de forma inapropiada, darán lugar a una complejidad extra innecesaria sin proporcionar ningún valor.

Entonces, ¿cuáles son los problemas que el patrón del repositorio intenta resolver?

1- Minimizando la lógica de consulta duplicada: en aplicaciones grandes, puede encontrar muchas consultas LINQ complejas duplicadas en algunos lugares. Si ese es el caso, puede usar el patrón de repositorio para encapsular estas consultas y minimizar la duplicación.

2- mejor separación de las preocupaciones: Imagínese una consulta compleja para obtener los cursos más vendidos en una categoría determinada que implica la carga ansiosa, unión, agrupación, filtrado, etc.

Cuando se implementa tan complejo grande consultas en sus servicios/controladores, terminará con servicios/controladores gordos. Estas clases se vuelven difíciles de probar por unidad, ya que requerirán una gran cantidad de ruido. Las pruebas de su unidad se vuelven largas, gordas e imposibles de mantener.

Si se enfrenta a este problema, quizás considere usar el patrón de repositorio. En este ejemplo, podemos encapsular la consulta compleja para obtener cursos vendidos en un repositorio:

courseRepository.GetTopSellingCourses(int categoryId, int count); 

De esta manera, sus servicios/controlador ya no hacer frente a la carga con ganas, unión, agrupación, etc. En cambio, Delegará en el repositorio. Recuerde, la carga ansiosa, la unión y la agrupación, etc. consultan la lógica y pertenecen a su capa de acceso a datos, no a sus servicios o capa de presentación.

3- desacoplamiento su arquitectura de la aplicación de los marcos de persistencia: cuando utiliza clases de Entity Framework (por ejemplo DbContext, DbSet, etc.) directamente en su aplicación, su aplicación está estrechamente unida al marco de la entidad. Si planea cambiar a un O/RM diferente en el futuro, o incluso una versión más nueva de Entity Framework con un modelo diferente, es posible que tenga que modificar muchas partes de su aplicación y esto puede generar nuevos errores en su aplicación. Puede usar el patrón de repositorio para desacoplar la arquitectura de su aplicación de los marcos de persistencia como Entity Framework. De esta manera, tendrá la libertad de cambiar a un O/RM diferente con un impacto mínimo en su aplicación.

Vea este video para más detalles:

https://youtu.be/rtXpYpZdOzM

0

usted debe considerar el "comando/objetos de consulta" como alternativa, se puede encontrar un montón de artículos interesantes en esta zona, pero aquí hay una buena:

https://rob.conery.io/2014/03/03/repositories-and-unitofwork-are-not-a-good-idea/

se podría pegarse a un único objeto de comando por comando para habilitar transacciones simples, evitando la necesidad de la complejidad de la Unidad de patrón de trabajo.

Sin embargo, si está pensando que un objeto Query por consulta es exagerado, podría estar 100% en lo cierto. A menudo, puede optar por comenzar con un objeto 'FooQueries', que es esencialmente un Repositorio pero solo para Consultas. 'Foo' podría ser su 'agregado de dominio' en el sentido DDD.

Puede encontrar objetos de consulta individuales que valen la pena más adelante.

Al igual que con la mayoría de las cosas que debe tener en cuenta sistema por sistema.

Cuestiones relacionadas