c# - unit - repository pattern obsolete
¿La Unidad de trabajo y los patrones de repositorio son muy útiles para grandes proyectos? (4)
Estoy empezando un nuevo proyecto web utilizando ASP.NET Webforms + EF4. Estoy tratando de aplicar un patrón de repositorio con una unidad de patrón 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
Creo que se me ocurrió la idea, pero mi pregunta es que, cuando creo un nuevo objeto en el modelo, ¿también tengo que definir ese objeto en IDALContext de la Unidad de Trabajo? ¿No es eso una ruptura de manos para un desarrollo rápido? Además, si trabaja con múltiples desarrolladores y no desea que otros desarrolladores vean su DAL, ¿cómo puede gestionar esto? Porque en este patrón, según entiendo, cuando creas un nuevo objeto en el modelo, también tienes que definirlo en el IDALContext para este tutorial. Lo siento, estoy tan confundido por esto.
Ahora, la primera pregunta debería ser, ¿por qué necesito un repositorio o unidad de patrón de trabajo? ¿No podría simplemente usar el contexto EF desde el 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, la calidad y el código más fácil de mantener. Si separa el acceso a los datos y se concentra en un solo lugar, puede simularse durante las pruebas. Esto le permite realizar una prueba unitaria de la lógica definida dentro de su controlador sin tener que escribir efectivamente en un almacén de datos.
Antes de comenzar con la Unidad de Trabajo, simplemente eche un vistazo al patrón del Repositorio . Esto básicamente abstrae el acceso a los datos para una entidad dada. Así que define métodos como Filtro (), Todos (), Actualizar (..), Insertar (..), Eliminar (...) y finalmente, Guardar (). En realidad, la mayoría de estos se podrían abstraer fácilmente a una BaseRepository<TEntity>
tal que al final solo tendría que crear un nuevo repositorio en casos raros con un comportamiento especial. De lo contrario, sería algo como BaseRepository<Person> personRepo = new BaseRepository<Person>()
o BaseRepository<Address> addressRepo = new BaseRepository<Address>()
etc.
¿Por qué se necesita la Unidad de Trabajo?
Una unidad de trabajo representa todas las operaciones realizadas durante un ciclo determinado, en un entorno web normalmente por solicitud de HTTP. Esto significa que cuando ingresa una nueva solicitud, crea una instancia de una nueva Unidad de trabajo, agrega nuevas cosas, la actualiza o elimina y luego "confirma" los cambios al invocar .save()
o .commit()
..whatever. En realidad, si analiza de cerca el Entity Framework DbContext (o ObjectContext), ya están representando algún tipo de Unidad de Trabajo.
Sin embargo, si desea abstraerlo aún más, ya que no necesariamente le gustaría tener su contexto EF en sus clases de controlador (recuerde: capacidad de prueba), cree un UoW para agrupar sus repositorios y también para asegurarse de que todos compartan el mismo EF instancia de contexto. Puede lograr esto último también a través de un contenedor DI (contenedor de inyección de dependencia).
A tus preguntas: ¿Es útil en grandes proyectos? :
Definitivamente, sobre todo en grandes proyectos. Se trata de mantener las responsabilidades separadas (acceso a datos, lógica de negocios, lógica de dominio) y, por lo tanto, hacer que las cosas sean verificables.
Debería considerar "objetos de comando / consulta" como una alternativa, puede encontrar un montón de artículos interesantes en esta área, pero aquí hay uno bueno:
https://rob.conery.io/2014/03/03/repositories-and-unitofwork-are-not-a-good-idea/
Se apegaría a un solo objeto de comando por comando para habilitar transacciones simples, evitando la necesidad de la complejidad del patrón de Unidad de Trabajo.
Sin embargo, si piensa que un objeto de consulta por consulta es una exageración, bien podría estar al 100% correcto. A menudo, puede elegir 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 de DDD.
Puede encontrar objetos de consulta individuales que valgan la pena más tarde.
Como con la mayoría de las cosas, hay que considerar sistema por sistema.
Martin Fowler describe la función del repositorio como: "Un repositorio media entre el dominio y las capas de asignación 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. También EF tiene una unidad de trabajo integrada. Por lo tanto, mi consejo es ignorar el artículo del blog que mencionó en su pregunta.
El código como este no solo es inútil o sin valor, sino que también es peligroso porque no se agrega 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 teniendo alguna abstracción que media entre el dominio y las capas de asignación de datos, actuar como una colección de objetos de dominio en memoria es una necesidad para proyectos "grandes". Y tener un mecanismo UnitOfWork bajo el capó puede ayudar a desacoplar la lógica de su negocio del acceso a una abstracción de acceso a algunos datos.
TL; TR; Repository y UnitOfWork pueden ayudarlo, pero no lo aplique como en la publicación del blog.
Los patrones de diseño de software están diseñados para resolver problemas específicos con el contexto adecuado y, si se usan de manera inadecuada, conducirán a una complejidad adicional innecesaria sin proporcionar ningún valor.
Entonces, ¿cuáles son los problemas que el patrón de repositorio pretende resolver?
1- Minimización de la lógica de consultas duplicadas : 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 inquietudes: imagine una consulta compleja para obtener los cursos más vendidos en una categoría determinada que implique cargar con entusiasmo, unirse, agruparse, filtrar, etc.
Cuando implementa consultas tan grandes y complejas en sus servicios / controladores, terminará con servicios / controladores grandes. Estas clases se vuelven difíciles de probar, ya que requerirán una gran cantidad de golpes ruidosos. Las pruebas de tu unidad se vuelven largas, gordas y no se pueden mantener.
Si estás enfrentando este problema, quizás podrías considerar usar el patrón de repositorio. En este ejemplo, podemos encapsular la consulta compleja para obtener los cursos más vendidos en un repositorio:
courseRepository.GetTopSellingCourses(int categoryId, int count);
De esta manera, sus servicios / controlador ya no se ocuparán de cargar, agrupar, agrupar, etc., sino que delegarán en el repositorio. Recuerde, las tareas de carga, unión y agrupación, etc., son lógicas de consulta y pertenecen a su capa de acceso a datos, no a sus servicios o capa de presentación.
3- Desacoplar la arquitectura de su aplicación de los marcos de persistencia: cuando usa las clases de Entity Framework (por ejemplo, DbContext, DbSet, etc.) directamente en su aplicación, su aplicación está estrechamente relacionada con Entity Framework. Si planea cambiar a un O / RM diferente en el futuro, o incluso a una versión más reciente de Entity Framework con un modelo diferente, es posible que tenga que modificar muchas partes de su aplicación y esto puede llevar a 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 una O / RM diferente con un impacto mínimo en su aplicación.
Echa un vistazo a este video para más detalles: