Using the Repository pattern, is it proper to return an IQueryable of a data set (table), for generic usage?

It is very handy in many cases, especially when using external libraries that leverage that interface, for example some plugins that sort/filter and bind to ui elements.

However, exposing an IQueryable sometimes seems to leave the design prone to errors. This, coupled with a wrong usage of lazy loading could lead to severe performance hits.

On the other hand, having access methods for every single usage seems redundant and also a lot of work (considering unit tests etc).

  • 2
    IMO : Hiding persistence technology (EF, NHibernate) from developers is bad idea. Just expose what this technology exposes. – Euphoric Aug 27 '12 at 8:19
  • @Euphoric Ok, but if in ASP.NET MVC I have controllers with 3000 lines where people happily create new DbContext() whenever they need and call SaveChanges() whenever they want. It is not possible to test anything and only thing I can think of is additional layer hiding it. – Mateusz May 7 '15 at 14:03
  • @Mateusz That is not problem of technology, but of people. You either have crappy developers or crappy management, who is unable to properly train said developers. – Euphoric May 7 '15 at 14:19

Mark Seemann has an excellent blog post about this subject: IQueryable is Tight Coupling. He sums it up nicely in the final part (emphasis mine):

You may think this is all a theoretical exercise, but it actually does matter. When writing Clean Code, it's important to design an API in such a way that it's clear what it does.

An interface like this makes false guarantees:

public interface IRepository
    IQueryable<T> Query<T>();

According to the LSP and Postel's law, it would seem to guarantee that you can write any query expression (no matter how complex) against the returned instance, and it would always work.

In practice, this is never going to happen.

Programmers who define such interfaces invariably have a specific ORM in mind, and they implicitly tend to stay within the bounds they know are safe for that specific ORM. This is a leaky abstraction.

If you have a specific ORM in mind, then be explicit about it. Don't hide it behind an interface. It creates the illusion that you can replace one implementation with another. In practice, that's impossible. Imagine attempting to provide an implementation over an Event Store.

The cake is a lie.

ORM's like Entity Framework are implementations of the Repository and the Unit of Work pattern. There's no need to wrap them in another one.

  • Thanks for the reply. Seems that my concerns meet those of Seemann's many times, but I havent actually taken the time to read him, which I intend to. The only thing I disagree with is that a repository -even if strongly coupled- is very useful to encapsulate business logic, even if at a simpler access level (ie: VisibleItems, DeletedItems) etc, and help with DRY concept. – Mihalis Bagos Aug 28 '12 at 12:08
  • @Kristof Just a question to "Entity Framework are implementations of the Repository and the Unit of Work pattern". What I can to so people don't put new DbContext() in controller and complex logic in single method in MVC and then don't put also some logic in the views? I have legacy code where I cannot do any unit testing. To enable testing and prevent people from doing really bad code I need additional layer. Therfore I need to implement my own repositories for educational purposes. – Mateusz May 7 '15 at 14:00
  • There are other options like service classes or command and query classes. – Kristof Claes May 7 '15 at 14:22

There will be no consensus on this one. In my opinion and experience, a Repository should return objects with specific uses. At leas if you use Repository Pattern as defined by Eric Evens in DDD. A Repository is a "bridge" connecting business logic, persistence and factories.

If you would like access to persistence more directly, maybe you are looking for the Gateway Pattern.

However, from what you say here, you would like to hide that exposure to persistence so the Proxy Pattern may com in handy for you.

  • While exposure to persistence is not a primary concern, at least a top level abstraction for patterns like parent-child entities is mandatory. I will look into those patterns also, thank you! – Mihalis Bagos Aug 28 '12 at 12:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.