Me pregunto cómo debería agrupar 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 eso parece una gran cantidad de repositorios que lo llevan a tener que llamar a muchos repositorios más adelante 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 reviso para ver si existe en la base de datos. Ahora, ¿qué sucede si necesito verificar esta clave de licencia o algo más de esa tabla en algún otro lugar que no sea el registro?
Un lugar podría ser el inicio de sesión (verifique si la clave no está vencida).
Entonces, ¿qué haría yo en esta situación? ¿Reescribe el código nuevamente (rompe DRY)? Intente combinar estos 2 repositorios juntos y espere que ninguno de los métodos sea necesario en algún otro momento (como si pudiera tener un método que verifique si se usa userName, tal vez lo necesite en otro lugar).
Además, si los fusiono, necesitaría 2 capas de servicio que vayan al 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 tener un nombre extraño?
Parece difícil crear un repositorio que tenga un nombre lo suficientemente general para que pueda usarlo en muchos puntos de su aplicación y aún así tenga sentido, y no creo que llamar a otro repositorio en un repositorio sea una buena práctica.
fuente
Respuestas:
Una cosa que hice mal cuando jugué con el patrón del repositorio: al igual que tú, pensé que la tabla se relaciona con el repositorio 1: 1. Cuando aplicamos algunas reglas de Domain Driven Design, el problema de agrupación de repositorios suele desaparecer.
El repositorio debe ser por raíz agregada y no por tabla. Significa que, si la entidad no debería vivir sola (es decir, si tiene una
Registrant
que participa en particularRegistration
), es solo una entidad, no necesita un repositorio, debería actualizarse / crearse / recuperarse a través del repositorio de raíz agregada. 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 se puede aplicar porque se supone que cada entidad es una raíz agregada (que depende en gran medida de su dominio, Solo puedo proporcionar conjeturas a ciegas). En su ejemplo,
License
parece ser una raíz agregada porque necesita poder verificarlos sin contexto deRegistration
entidad.Pero eso no nos limita a los repositorios en cascada (el
Registration
repositorio puede hacer referencia alLicense
repositorio si es necesario). Eso no nos limita a hacer referencia alLicense
repositorio (preferiblemente, a través de IoC) directamente desde elRegistration
objeto.Simplemente trate de no conducir su diseño a través de complicaciones proporcionadas por tecnologías o malentendidos. Agrupar los repositorios
ServiceX
solo porque no desea construir 2 repositorios no es una buena idea.Mucho mejor sería darle un nombre propio,
RegistrationService
es decirPero los servicios deben evitarse en general; a menudo son una causa que conduce a un modelo de dominio anémico .
EDITAR:
comience 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 servicios comunes, pero eso es solo un ejemplo.
fuente
Una cosa que comencé a hacer para abordar esto es desarrollar servicios que envuelvan N repositorios. Con suerte, sus marcos de DI o IoC pueden ayudar a facilitarlo.
public class ServiceImpl { public ServiceImpl(IRepo1 repo1, IRepo2 repo2...) { } }
¿Tiene sentido? Además, entiendo que hablar de servicios en esta mansión puede o no cumplir con los principios de DDD, solo lo hago porque parece funcionar.
fuente
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); }
Luego, puede derivar su repositorio de la clase base abstracta y extender su repositorio único siempre que los argumentos genéricos difieran, por ejemplo;
public class RegistrationRepository: ReadOnlyRepository<int, IRegistrationItem>, ReadOnlyRepository<string, IRegistrationItem>
etc ....
Necesito los repositorios separados porque tenemos restricciones en algunos de nuestros repositorios y esto nos da la máxima flexibilidad. Espero que esto ayude.
fuente
Tengo esto como mi clase de repositorio y sí, lo extiendo en el repositorio de tabla / área, pero 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 a la pregunta de DRY aunque no lo creo.
fuente
Aquí hay un ejemplo de una implementación de Repositorio genérico usando FluentNHibernate. Es capaz de conservar cualquier clase para la que haya escrito un asignador. Incluso es capaz de generar su base de datos basada en las clases del asignador.
fuente
El patrón de repositorio es un patrón de diseño incorrecto. Trabajo con muchos proyectos .Net antiguos y este patrón suele provocar errores de "Transacciones distribuidas", "Reversión parcial" y "Grupo de conexiones agotado" que podrían evitarse. El problema es que el patrón intenta manejar conexiones y transacciones internamente, pero deben manejarse en la capa del controlador. Además, EntityFramework ya abstrae gran parte de la lógica. Sugeriría usar el patrón de servicio en su lugar para reutilizar el código compartido.
fuente
Te sugiero que mires Sharp Architecture . Sugieren usar un repositorio por entidad. Lo estoy usando actualmente en mi proyecto y estoy satisfecho con los resultados.
fuente