Building a custom predicate to act as a filter using a foreach loop

微笑、不失礼 提交于 2019-12-05 13:10:18

I don't understand why you do this:

innerPredicate = innerPredicate.Or(d => inPeriod.Invoke(d));

When you could just avoid the Invoke completely, like this:

innerPredicate = innerPredicate.Or(inPeriod);

This should work perfectly fine.


BTW, I have a feeling there's a bug with LINQKit here (unless there's some documentation that suggests that it doesn't support this scenario).

When I tried this similar code:

 Expression<Func<int, bool>> first = p1 => p1 > 4;
 Expression<Func<int, bool>> second = p2 => p2 < 2;

// Expand is similar to AsExpandable, except it works on 
// expressions, not queryables.
var composite = first.Or(d => second.Invoke(d))
                     .Expand();

...LINQKit generated the following composite expression:

p1 => ((p1 > 4) OrElse (d < 2)) // what on earth is d?

... which indeed has the unbound parameter d (NodeType = Parameter, Name = 'd').

Dodging the Invoke with first.Or(second).Expand() generates the perfectly sensible:

p1 => ((p1 > 4) OrElse (p1 < 2)) // much better now...

Finally, I have found a way to avoid combining multiple predicates to the main expression tree.

Given that each predicate represents a different filter and I want the final, combined filter to be a series of must-be-respected conditions, we can say that each of the predicates has to return true for the final predicate to return true.

For that to work, the predicates has to be combined with AND. So, the resulting SQL query must look like this :

predicate1 AND predicate2 AND predicate3 ...

A better way to combine these predicates with AND is to chain Where query operators to the final query, like this :

var documents = this.ObjectSet.AsExpandable()
    .Where(mainPredicate)
    .Where(otherPredicate)
    .Where(yetAnotherPredicate)
    .ToList();

The resulting SQL query will combine each of these predicates with AND. That is just what I wanted to do.

It is easier than hacking out an expression tree by myself.

I use these extension methods:

public static class Extensions
{
    public static Expression<Func<T, bool>> OrElse<T>(this Expression<Func<T, bool>> source, Expression<Func<T, bool>> predicate)
    {
        InvocationExpression invokedExpression = Expression.Invoke(predicate, source.Parameters.Cast<Expression>());
        return Expression.Lambda<Func<T, bool>>(Expression.OrElse(source.Body, invokedExpression), source.Parameters);
    }

    public static Expression<Func<T, bool>> AndAlso<T>(this Expression<Func<T, bool>> source, Expression<Func<T, bool>> predicate)
    {
        InvocationExpression invokedExpression = Expression.Invoke(predicate, source.Parameters.Cast<Expression>());
        return Expression.Lambda<Func<T, bool>>(Expression.AndAlso(source.Body, invokedExpression), source.Parameters);
    }

}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!