How can I write a clean Repository without exposing IQueryable to the rest of my application?

iqueryable, linq-to-sql, repository, repository-pattern

Solution

Exposing an `IQueryable` is a very viable solution and this is how most of the Repository implementations out there doing right now. (Including SharpArchitecture and FubuMVC contrib, as well.)

This is where you are wrong:

However, if you aren't using IQueryable then methods like GetAll() aren't really practical since lazy evaluation won't be taking place down the line. I don't want to return 10,000 records only to use 10 of them later.

This is not realy true. Your example is correct and you should rename GetAll() to a more informative name.

It DOESN'T return all of the items if you call it. That is what IQueryable is for. The concept is called "deferred loading", as it only loads the data (and makes database requests) when you enumerate the `IQueryable`.

So, let's say I have a method like this:

IQueryable<T> Retrieve() { ... }

Then, I can call it like this:

Repository.Retrieve<Customer>().Single(c => c.ID == myID);

This ONLY retrieves one row from the database.

And this:

Repository.Retrieve<Customer>().Where(c => c.FirstName == "Joe").OrderBy(c => c.LastName);

This also generates a corresponding query and is only executed when you enumerate it. (It generates an expression tree from the query, and then the query provider should translate that into an appropriate query against the data source.)

You can read more about it in this MSDN article.

Problem

So, I've read all the Q&A's here on SO regarding the subject of whether or not to expose IQueryable to the rest of your project or not (see here, and here), and I've ultimately decided that I don't want to expose IQueryable to anything but my Model. Because IQueryable is tied to certain persistence implementations I don't like the idea of locking myself into this. Similarly, I'm not sure how good I feel about classes further down the call chain modifying the actual query that aren't in the repository. So, does anyone have any suggestions for how to write a clean and concise Repository without doing this? One problem I see, is my Repository will blow up from a ton of methods for various things I need to filter my query off of. Having a bunch of: ``` IEnumerable GetProductsSinceDate(DateTime date); IEnumberable GetProductsByName(string name); IEnumberable GetProductsByID(int ID); ``` If I was allowing IQueryable to be passed around I could easily have a generic repository that looked like: ``` public interface IRepository<T> where T : class { T GetById(int id); IQueryable<T> GetAll(); void InsertOnSubmit(T entity); void DeleteOnSubmit(T entity); void SubmitChanges(); } ``` However, if you aren't using IQueryable then methods like GetAll() aren't really practical since lazy evaluation won't be taking place down the line. I don't want to return 10,000 records only to use 10 of them later. What is the answer here? In Conery's MVC Storefront he created another layer called the "Service" layer which received IQueryable results from the respository and was responsible for applying various filters. Is this what I should do, or something similar? Have my repository return IQueryable but restrict access to it by hiding it behind a bunch of filter classes like GetProductByName, which will return a concrete type like IList or IEnumerable?

Original source

Related problems