0

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.

Community
  • 1
  • 1
Pouya Samie
  • 3,718
  • 1
  • 21
  • 34
  • Don't return an IQueryable, but *take one* that can be used as a filter. Such as `public SomeType[] Get(IQueryable filter)` which is easy to use `var result = someTypeRepo.Get(x => x.Id > 0)`. –  Jan 09 '17 at 21:56
  • thank you will that actually can work easily – Pouya Samie Jan 11 '17 at 07:56
  • You can also take IQueryables that express navigation properties you want to include in the result, as well. –  Jan 11 '17 at 14:08
  • @Will this can help as i do now but after all i have to return all the data for filtering – Pouya Samie Jan 12 '17 at 07:55

1 Answers1

0

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);
}
jorgonor
  • 1,679
  • 10
  • 16
  • thank you for your reply so as you say for every report I should change my repository? because the client always ask for a new report and I should change my repository and I think it is violent the Open close principal – Pouya Samie Jan 05 '17 at 10:22
  • It might not be a comfy option if what you're doing is reporting. I was answering the case you asked. Even though, what you show is a scenario where requirements change, so will the BookFilter accordingly and support new filters you weren't supporting previously. Taking distance with the repository pattern, if what you're doing is reporting maybe you might opt out for using directly `IQueryable`, more if reports are likely to change or grow. – jorgonor Jan 05 '17 at 10:26
  • thank you that was exactly I was confused about – Pouya Samie Jan 05 '17 at 10:34
  • by the way i have updated my question for future clearity – Pouya Samie Jan 05 '17 at 10:39