Estamos desenvolvendo um aplicativo ASP.NET MVC e agora estamos construindo as classes de repositório / serviço. Eu estou querendo saber se há alguma grande vantagem em criar uma interface genérica de IRepository que todos os repositórios implementam, contra cada Repositório com sua própria interface e conjunto de métodos.
Por exemplo: uma interface genérica de IRepository pode parecer (tirada desta resposta ):
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 repositório implementaria essa interface, por exemplo:
- CustomerRepository: IRepository
- ProductRepository: IRepository
- etc.
A alternativa que seguimos em projetos anteriores seria:
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);
}
No segundo caso, as expressões (LINQ ou não) estariam totalmente contidas na implementação do Repositório, quem estiver implementando o serviço só precisa saber para qual função do repositório chamar.
Acho que não vejo a vantagem de escrever toda a sintaxe da expressão na classe de serviço e passar para o repositório. Isso não significa que o código LINQ de fácil envio de mensagens está sendo duplicado em muitos casos?
Por exemplo, em nosso antigo sistema de faturamento, chamamos
InvoiceRepository.GetSingleInvoice(DateTime invoiceDate, int accountId)
de alguns serviços diferentes (cliente, fatura, conta etc.). Isso parece muito mais limpo do que escrever o seguinte em vários lugares:
rep.GetSingle(x => x.AccountId = someId && x.InvoiceDate = someDate.Date);
A única desvantagem que vejo ao usar a abordagem específica é que poderíamos terminar com muitas permutações das funções Get *, mas isso ainda parece preferível ao empurrar a lógica da expressão para as classes Service.
o que estou perdendo?