usar repositorios repositorio patrón patrones patron parte net implementación generico framework diseño c# .net asp.net asp.net-mvc repository-pattern

c# - repositorios - ¿Cómo usar el patrón de repositorio correctamente?



repositorio base c# (7)

El patrón Repositorio es un mal patrón de diseño. Trabajo con muchos proyectos .Net antiguos y este patrón típicamente causa "Transacciones distribuidas", errores de "Reversión parcial" y "Agrupación de conexiones" que podrían evitarse. El problema es que el patrón trata de manejar las conexiones y las transacciones internamente, pero esas deben manejarse en la capa de Controlador. Además, EntityFramework ya resume gran parte de la lógica. Sugeriría utilizar el patrón de Servicio en su lugar para reutilizar el código compartido.

Me pregunto ¿cómo debería estar agrupando mis repositorios? Como en los ejemplos que vi en asp.net mvc y en mis libros, básicamente usan un repositorio por tabla de base de datos. Pero parece que hay muchos repositorios que te llevan a tener que buscar muchos repositorios más tarde para burlarse y esas cosas.

Así que supongo que debería agruparlos. Sin embargo, no estoy seguro de cómo agruparlos.

En este momento hice un Repositorio de registro para manejar todas mis cosas de registro. Sin embargo, hay como 4 tablas que necesito actualizar y antes tenía 3 repositorios para hacer esto.

Por ejemplo, una de las tablas es una tabla de licencias. Cuando se registran, miro su clave y la compruebo para ver si existe en la base de datos. Ahora, ¿qué sucede si necesito verificar esta clave de licencia u otra cosa de esa tabla en algún otro lugar que no sea el registro?

Un punto podría ser el inicio de sesión (verifique si la clave no ha caducado).

Entonces, ¿qué haría en esta situación? Vuelva a escribir el código (romper DRY)? Intenta juntar estos 2 repositorios y espero que ninguno de los métodos sea necesario en algún otro momento (como por ejemplo, quizás tenga un método que compruebe si userName se usa, tal vez lo necesite en otro lugar).

Además, si los fusiono, necesitaría 2 capas de servicio para el mismo repositorio, ya que creo que tener toda la lógica para 2 partes diferentes de un sitio sería largo y tendría que tener nombres como ValidateLogin (), ValdiateRegistrationForm () , ValdiateLoginRetrievePassword () y etc.

¿O llamar al Repositorio de todos modos y solo tiene un nombre extraño?

Parece difícil crear un repositorio que tenga un nombre suficientemente general para que puedas usarlo en muchos lugares de tu aplicación y que aún tenga sentido, y no creo que llamar a otro repositorio en un repositorio sea una buena práctica.


Lo que estoy haciendo es que tengo una clase base abstracta definida de la siguiente manera:

public abstract class ReadOnlyRepository<T,V> { V Find(T lookupKey); } public abstract class InsertRepository<T> { void Add(T entityToSave); } public abstract class UpdateRepository<T,V> { V Update(T entityToUpdate); } public abstract class DeleteRepository<T> { void Delete(T entityToDelete); }

A continuación, puede derivar su repositorio de la clase base abstracta y extender su único repositorio siempre que los argumentos genéricos difieran por ejemplo;

public class RegistrationRepository: ReadOnlyRepository<int, IRegistrationItem>, ReadOnlyRepository<string, IRegistrationItem>

etc ....

Necesito los repositorios por separado porque tenemos restricciones en algunos de nuestros repositorios y esto nos da la máxima flexibilidad. Espero que esto ayude.


Te sugiero que mires a Sharp Architecture . Sugieren usar un repositorio por entidad. Lo estoy usando actualmente en mi proyecto y estoy muy contento con los resultados.


Tengo esto como mi clase de repositorio y sí lo extiendo en el repositorio de tabla / área, pero aún así a veces tengo que romper DRY.

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace MvcRepository { public class Repository<T> : IRepository<T> where T : class { protected System.Data.Linq.DataContext _dataContextFactory; public IQueryable<T> All() { return GetTable.AsQueryable(); } public IQueryable<T> FindAll(Func<T, bool> exp) { return GetTable.Where<T>(exp).AsQueryable(); } public T Single(Func<T, bool> exp) { return GetTable.Single(exp); } public virtual void MarkForDeletion(T entity) { _dataContextFactory.GetTable<T>().DeleteOnSubmit(entity); } public virtual T CreateInstance() { T entity = Activator.CreateInstance<T>(); GetTable.InsertOnSubmit(entity); return entity; } public void SaveAll() { _dataContextFactory.SubmitChanges(); } public Repository(System.Data.Linq.DataContext dataContextFactory) { _dataContextFactory = dataContextFactory; } public System.Data.Linq.Table<T> GetTable { get { return _dataContextFactory.GetTable<T>(); } } } }

EDITAR

public class AdminRepository<T> : Repository<T> where T: class { static AdminDataContext dc = new AdminDataContext(System.Configuration.ConfigurationManager.ConnectionStrings["MY_ConnectionString"].ConnectionString); public AdminRepository() : base( dc ) { }

También tengo un contexto de datos que se creó utilizando la clase Linq2SQL.dbml.

Así que ahora tengo un repositorio estándar que implementa llamadas estándar como All y Find y en mi AdminRepository tengo llamadas específicas.

No responde la pregunta de DRY aunque no lo creo.


Una cosa que he empezado a hacer para abordar esto es desarrollar realmente servicios que envuelvan repositorios de N. Es de esperar que sus marcos DI o IoC puedan ayudarlo a hacer eso más fácil.

public class ServiceImpl { public ServiceImpl(IRepo1 repo1, IRepo2 repo2...) { } }

¿Tiene sentido? Además, entiendo que hablar de servicios en esta casa puede o no cumplir con los principios de la DDD, simplemente lo hago porque parece funcionar.


Una cosa que hice mal cuando jugué con el patrón de repositorio: al igual que tú, pensé que la tabla se relaciona con el repositorio 1: 1. Cuando aplicamos algunas reglas desde el Diseño Dirigido por Dominio - el problema de repositorios de agrupaciones a menudo desaparece.

El repositorio debe ser por raíz agregada y no por tabla. Significa que, si la entidad no debe vivir sola (es decir, si tiene un Registrant que participa en un Registrant en particular), es solo una entidad, no necesita un repositorio, debe ser actualizada / creada / recuperada a través del repositorio de agregado. raíz a la que pertenece.

Por supuesto, en muchos casos, esta técnica de reducir el recuento de repositorios (en realidad, es más una técnica para estructurar su modelo de dominio) no puede aplicarse porque se supone que cada entidad es una raíz agregada (que depende en gran medida de su dominio, Puedo proporcionar conjeturas ciegas solamente). En su ejemplo, la License parece ser una raíz agregada porque necesita poder verificarlos sin contexto de entidad de Registration .

Pero eso no nos restringe a repositorios en cascada (el repositorio de Registration puede hacer referencia al repositorio de License si es necesario). Eso no nos restringe a hacer referencia al repositorio de License (preferiblemente a través de IoC) directamente desde el objeto de Registration .

Simplemente intente no impulsar su diseño a través de complicaciones proporcionadas por las tecnologías o malentendidos. Agrupar repositorios en ServiceX simplemente porque no quiere construir 2 repositorios no es una buena idea.

Mucho mejor sería darle un nombre propio - RegistrationService ie

Pero los servicios deben evitarse en general; a menudo son causa que conduce a un modelo de dominio anémico .

EDITAR:
Empieza a usar IoC. Realmente alivia el dolor de inyectar dependencias.
En lugar de escribir:

var registrationService = new RegistrationService(new RegistrationRepository(), new LicenseRepository(), new GodOnlyKnowsWhatElseThatServiceNeeds());

Podrás escribir:

var registrationService = IoC.Resolve<IRegistrationService>();

Ps: Sería mejor usar el llamado localizador de servicio común, pero eso es solo un ejemplo.


Aquí hay un ejemplo de una implementación de Repositorio genérico usando FluentNHibernate. Es capaz de persistir en cualquier clase para la que haya escrito un asignador. Incluso es capaz de generar su base de datos a partir de las clases de asignador.