5

I am implementing a repository pattern. My main reasons for this:

  • To abstract client code away from persistence specifics (Entity Framework)
  • To support testability

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.

enter image description here

  • How would this effect unit testing? Would I still be able to Mock the ICustomerRepository with this implementation?

  • How would this effect swopping out my persistence layer? Like Azure Storage Tables or NHibernate.

Otherwise I would have to implement very specific query method on 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.

Dave New
  • 38,496
  • 59
  • 215
  • 394
  • 1
    similar: http://stackoverflow.com/q/7411504/861716 – Gert Arnold Dec 11 '13 at 08:01
  • 1
    also similar: http://stackoverflow.com/q/6051145/150342 – Colin Dec 11 '13 at 08:53
  • Thanks for the links, but I am still a little unclear about testing. Why can't I mock with the IQueryable? – Dave New Dec 11 '13 at 09:21
  • 1
    You can mock/moq with IQueryable. http://msdn.microsoft.com/en-us/data/dn314429 ... The point Gert has linked has link unless you are carfull about how you declare your IREPOSITORY and you can end up leaking EF specifics. Mocking EF is not straight forward, BUT your DOmain/Core layer where you should declare IRrespository should have NO reference to EF. – phil soady Dec 11 '13 at 10:36
  • Oh, and I also wrote [this](http://stackoverflow.com/questions/13332002/how-to-mock-the-limitations-of-entityframeworks-implementation-of-iqueryable/13352779#13352779) about mocking. I can't help it... – Gert Arnold Dec 11 '13 at 21:45
  • Why is 'IQueryable Query()' considered leaky? – Chalky Jun 10 '14 at 00:01
  • Because IQueryable is Link and Link is part of Entity Framework, EF extends Link, you use Link to query you I are saying I use EF only anywhere you do it. So passing IQueryable around in your app is like saying, hey app, we use EF extended Link query language, you will no longer build if I change to another ORM besides EF. – Brian Ogden Jun 14 '14 at 01:29
  • IQueryable gets used and you just tied yourself to the ORM it can no longer be swapped out. The Repository pattern and UOW pattern is just a waste of time. Entity Framework ORM is the abstraction already and you just isolate yourself from its power with the repository pattern. – Brian Ogden Jun 14 '14 at 01:30
  • http://lostechies.com/jimmybogard/2012/10/08/favor-query-objects-over-repositories/ – Brian Ogden Jun 14 '14 at 01:30
  • http://tech.pro/blog/1191/say-no-to-the-repository-pattern-in-your-dal – Brian Ogden Jun 14 '14 at 01:31
  • http://www.wekeroad.com/2014/03/04/repositories-and-unitofwork-are-not-a-good-idea/ – Brian Ogden Jun 14 '14 at 01:32

1 Answers1

3

You can have a relatively clean IRepository<T> by sticking to the pattern.

Data Access LAyer

  • reference to EF and Core project
  • Has Respository<T> : IRepository<T>
  • Option has IEFJunk declaration (Only if using multiple repositories)
  • Reference to Core
  • Respository is injected with Context (typically during instantiation)

Core

  • Interfaces that can be "Injected"
  • IRepository declaration. With no EF data type use.
  • NO reference to EF

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

phil soady
  • 11,043
  • 5
  • 50
  • 95