Estamos desarrollando una aplicación ASP.NET MVC y ahora estamos creando las clases de repositorio / servicio. Me pregunto si existen ventajas importantes para crear una interfaz genérica de IRepository que implementen todos los repositorios, en comparación con cada Repository que tenga su propia interfaz única y un conjunto de métodos.
Por ejemplo: una interfaz genérica de IRepository podría verse así (tomada de esta respuesta ):
public interface IRepository : IDisposable
{
T[] GetAll<T>();
T[] GetAll<T>(Expression<Func<T, bool>> filter);
T GetSingle<T>(Expression<Func<T, bool>> filter);
T GetSingle<T>(Expression<Func<T, bool>> filter, List<Expression<Func<T, object>>> subSelectors);
void Delete<T>(T entity);
void Add<T>(T entity);
int SaveChanges();
DbTransaction BeginTransaction();
}
Cada repositorio implementaría esta interfaz, por ejemplo:
- CustomerRepository: IRepository
- ProductRepository: IRepository
- etc.
La alternativa que hemos seguido en proyectos anteriores sería:
public interface IInvoiceRepository : IDisposable
{
EntityCollection<InvoiceEntity> GetAllInvoices(int accountId);
EntityCollection<InvoiceEntity> GetAllInvoices(DateTime theDate);
InvoiceEntity GetSingleInvoice(int id, bool doFetchRelated);
InvoiceEntity GetSingleInvoice(DateTime invoiceDate, int accountId); //unique
InvoiceEntity CreateInvoice();
InvoiceLineEntity CreateInvoiceLine();
void SaveChanges(InvoiceEntity); //handles inserts or updates
void DeleteInvoice(InvoiceEntity);
void DeleteInvoiceLine(InvoiceLineEntity);
}
En el segundo caso, las expresiones (LINQ o de otro tipo) estarían completamente incluidas en la implementación del Repositorio, quien implementa el servicio solo necesita saber a qué función del repositorio llamar.
Supongo que no veo la ventaja de escribir toda la sintaxis de expresión en la clase de servicio y pasarla al repositorio. ¿No significa esto que el código LINQ fácil de enredar se está duplicando en muchos casos?
Por ejemplo, en nuestro antiguo sistema de facturación, llamamos
InvoiceRepository.GetSingleInvoice(DateTime invoiceDate, int accountId)
de algunos servicios diferentes (Cliente, Factura, Cuenta, etc.). Eso parece mucho más limpio que escribir lo siguiente en varios lugares:
rep.GetSingle(x => x.AccountId = someId && x.InvoiceDate = someDate.Date);
La única desventaja que veo al usar el enfoque específico es que podríamos terminar con muchas permutaciones de las funciones Get *, pero esto todavía parece preferible a empujar la lógica de expresión hacia las clases de Servicio.
¿Qué me estoy perdiendo?