Not exposing IQueryable and not violating OC principle

275 Views Asked by At

I was reading about the repository pattern the last few days and everyone talking about it do not expose IQueryable from repository like this (like here and here):

public interface ICustomersRepository
{
    IQueryable<Customer> Customers{ get; }
}

And it is accepted by large amount of developers to avoid this.

But when it comes to filtering large amount of data and custom filters from UI (like a report with over 10 filter options for searching in data over 1 million records) is IQueryable?

Especially when there is a framework and other low-level developers are using the repository for developing custom reports. They can not always use GetAll for this purpose.

So as mentioned in other threads like this or this, I should have methods for each one of the reports that I have in my repositories, and they should return IEnumerable. Here is what is not clear to me:

If I have a new report I have to change my repository for that and add a new method. And if I change my repository I've violated the Open/Close principle.

Here is my problem: I don't want to expose Iqueryable and on the other hand, I don't want to change my repository for every report.

1

There are 1 best solutions below

4
On BEST ANSWER

A repository is an abstraction over your Data Access Layer (DAL). In Java, they are also known as DAOs (Data Access Objects). So, exposing IQueryable<T> in a repository is bad practice because of this reason, you are tying LINQ queries to the client code.

So, to fix it you should create an object which would follow the command pattern with all the filtering options you support. Then return a List<T> or any sorted collection you want to use (maybe IList<T> is more appropriate).

An example

class BookFilter
{
    public string NameStartsWith { get; set; }
    public string ISBN { get; set; }
    public DateTime PublishedAfter { get; set; }
    // ....
}

public interface IBookRepository  
{
    IList<Book> Filter(BookFilter filter);
}