I am implementing a repository pattern. My main reasons for this is:
Generic Repository or not?
The issue I have run into is whether I should have a generic repository or not. An IQueryable<T> Query()
method would provide the calling code with means to construct specific queries. The issue here is that this is leaky abstraction - Entity Framework specifics are now leaking into my client code.
I want to know:
how would this affect unit testing? Would I still be able to Mock the ICustomerRepository
with this implementation?
how would this effect swap out my persistence layer? Like Azure Storage Tables or NHibernate.
Otherwise, I would have to implement very specific query methods on the ICustomerRepository
, such as GetIsActiveByFirstName()
and GetIsActiveByDistrict()
. I dislike this a lot as my repository classes are going to become jam-packed with different query methods. This system has hundreds of models and so there could be hundreds or even thousands of these methods to write and maintain.
You can have a relatively clean IRepository<T>
by sticking to the pattern.
Data Access LAyer
Respository<T> : IRepository<T>
Core
So now code in Core you can refer to an IRepository<t>
.
The implementing class can have EF specifics. But this can not be accessed from core!
so you can have IQueryable.
public interface IRepositoryBase<TPoco>{
IQueryable<TPoco> GetListQ(Expression<Func<TPoco, bool>> predicate);
//...
BUt if you decided you wanted to add
//...
// logically exposing IQueryable<T> Include<T>(this IQueryable<T> source, string path) from EF
IQueryable<TPoco> IncludeNAVProp(string navToInclude);
}
Then the Repository implementation
return Context.Set<TPoco>().Include(navToInclude);
requires the underlying provider to be EF. So now mocking is against an actual EF provider.
And unless you are careful, EF specific code. leaks out.
Indeed the interface IRepository that has the CONCEPT "include" can already be considered LEAKY.
Keeping EF specifics out of your Interfaces, is the key to avoiding the leaks.
And you can have 1 IRepository<t>
and 1 Respository<t>
and support 100s of tables