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