9

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).

3
  • 2
    IMO : Hiding persistence technology (EF, NHibernate) from developers is bad idea. Just expose what this technology exposes. Commented Aug 27, 2012 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. Commented May 7, 2015 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. Commented May 7, 2015 at 14:19

2 Answers 2

12

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.

3
  • 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. Commented Aug 28, 2012 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. Commented May 7, 2015 at 14:00
  • There are other options like service classes or command and query classes. Commented May 7, 2015 at 14:22
1

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.

1
  • 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! Commented Aug 28, 2012 at 12:12

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.