Мы разрабатываем приложение 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.
Что мне не хватает?
