Мы разрабатываем приложение ASP.NET MVC и сейчас создаем классы хранилища / службы. Мне интересно, есть ли какие-либо существенные преимущества в создании универсального интерфейса IRepository, который реализуют все репозитории, по сравнению с каждым репозиторием, имеющим свой уникальный интерфейс и набор методов.
Например: общий интерфейс IRepository может выглядеть так (взято из этот ответ ):
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();
}
Каждый репозиторий будет реализовывать этот интерфейс, например:
- CustomerRepository: IRepository
- ProductRepository: IRepository
- и т.д.
Альтернатива, которой мы следовали в предыдущих проектах, будет:
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);
}
Во втором случае выражения (LINQ или иным образом) будут полностью содержаться в реализации репозитория, и тому, кто реализует сервис, просто нужно знать, какую функцию репозитория вызывать.
Полагаю, я не вижу преимущества написания всего синтаксиса выражений в классе обслуживания и передачи в хранилище. Не означает ли это, что во многих случаях дублирующийся код LINQ легко повторяется?
Например, в нашей старой системе выставления счетов мы вызываем
InvoiceRepository.GetSingleInvoice(DateTime invoiceDate, int accountId)
из нескольких различных услуг (Клиент, Счет, Счет и т. Д.). Это кажется намного чище, чем писать следующее в нескольких местах:
rep.GetSingle(x => x.AccountId = someId && x.InvoiceDate = someDate.Date);
Единственный недостаток, который я вижу в использовании особого подхода, заключается в том, что мы можем получить множество перестановок функций Get *, но это все же кажется предпочтительным, чем проталкивать логику выражения в классы Service.
Что мне не хватает?