I have lots of tabular data that needs to be filtered, filtering is supposed to be available for each column in the data. The data is simple types, int, double, string, bool, date. Users specify the filtering conditions in the front end.
I'll just give the example for ints because the problem is the same no matter the data type.
I have lots of int columns across lots of different tables in the db. The filtering condition is to be able to apply a minimum filter to the data, so if the minimum is specified, no data smaller than the minimum gets through. Very simple.
I can do this easily with Linq and Entity Framework 6.
IQueryable<Data> data = db.Data;
data = data.Where(item => (filter.MinValue == null || filter.MinValue <= item.a))
With this solution I have to write this code snippet hundreds of times across the application. I would rather not do that. Worth noting at this point that there are some more complex cases, which are a pain to write out over and over again.
I have a function which contains the same logic.
public bool Min(int minValue, int value)
{
return minValue == null || value >= minValue;
}
If I try and use the function like this it will work happily.
List<Data> data = db.Data.ToList();
data = data.Where(item => Min(filter.MinValue, item.a))
I believe this uses Linq-to-objects.
If I try and use the function like this, it does not work.
IQueryable<Data> data = db.Data;
data = data.Where(item => Min(filter.MinValue, item.a))
I believe this uses Linq-to-entities.
I get this error:
System.NotSupportedException: LINQ to Entities does not recognize the method 'Boolean Min([System.Int], [System.Int])' method, and this method cannot be translated into a store expression.
This a well known bit of behaviour. The question I have is: is there a way I can package up the logic into something function-esque, that I can use with Linq-to-Entities in a repeatable way rather than just having to write out almost the same thing for every filter condition.
I need to be able to use Linq-to-Entities because filtering the data in memory is noticeably less performant.
I've looked at using predicates, but they seem to require me to know the object that the filter will be applied to, whereas I'm looking for a method I can apply to objects of any type (as long as they have the relevant field to filter by).
if (filter.MinValue!=null){ query=query.Where(item=>item.a >= filter.MinValue);}. You can put that into a function that receivesIQueryable<T> queryas input and returns the final queryLINQKit. It usesExpandableAttributeto mark methods, which needs Expression substitution.