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