Z.V
Z.V

Reputation: 1461

Apply multiple expression in linq

Having different kind of filter following used in different situation. How to apply more than 1 filter in a LinQ.

Expression<Func<data, bool>> filter =
                    bt => bt.condition1 == condition1;
Expression<Func<data, bool>> filter2 =
                    bt => bt.condition2 == condition2;
Expression<Func<data, bool>> filter3 =
                    bt => bt.condition3 == condition3;


var result = dataList.Where(filter1);
var result2 = dataList.Where(filter2, filter3); //Syntax error
var result3 = dataList.Where(filter2).Where(filter3); //Is this proper?
var result4 = dataList.Where(filter2 || filter3); //Syntax error

Upvotes: 0

Views: 4373

Answers (4)

user1023602
user1023602

Reputation:

It depends on the type of dataList.

If it's IEnumerable<data>, then you can use functions instead of expressions, and a lambda function for the Where clause:

Func<data, bool> filter =  (bt => bt.condition1 == condition1);
Func<data, bool> filter2 = (bt => bt.condition2 == condition2);
Func<data, bool> filter3 = (bt => bt.condition3 == condition3);

var all = dataList.Where(d => filter1(d) && filter2(d) && filter3(d));
var any = dataList.Where(d => filter1(d) || filter2(d) || filter3(d));

However if the type is IQueryable<data>, then you will need to use multiple calls to the Queryable version of Where:

var all = dataList.Where(filter1).Where(filter2).Where(filter3);

var any = dataList.Where(filter1)
                  .Union(dataList.Where(filter2))
                  .Union(dataList.Where(filter3))
                  .Distinct();

Upvotes: 2

anıl yıldırım
anıl yıldırım

Reputation: 963

Best practies,

var query = fooContext.User.AsQueryable();

if (condition1!= null)
    query = query.Where(x => x.condition1==condition1);
if (condition2 != null)
    query = query.Where(x => x.condition2== condition2 );

return await query.ToList();

Upvotes: 0

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249706

If you want to combine the conditions using and you can just use several where operators:

// equivalent to filter1 && filter2 && filter3
var result = dataList.Where(filter1).Where(filter2).Where(filter3); 

If you want to combine the filters using or it is a bit more complicated, you need to manually manipulate the expressions, I have this small util that can do that:

public static Expression<Func<T, bool>> CombineWithOr<T>(params Expression<Func<T, bool>>[] filters)
{
    var first = filters.First();
    var param = first.Parameters.First();
    var body = first.Body;

    foreach(var other in filters.Skip(1))
    {
        var replacer = new ReplaceParameter
        {
            OriginalParameter = other.Parameters.First(),
            NewParameter = param
        };
        // We need to replace the original expression parameter with the result parameter
        body = Expression.Or(body, replacer.Visit(other.Body));
    }

    return Expression.Lambda<Func<T, bool>>(
        body,
        param
    );
}
class ReplaceParameter : ExpressionVisitor
{
    public Expression OriginalParameter { get; set; }
    public Expression NewParameter { get; set; }
    protected override Expression VisitParameter(ParameterExpression node)
    {
        return node == this.OriginalParameter ? this.NewParameter : base.VisitParameter(node);
    }
}

Usage:

// equivalent to filter1|| filter2 || filter3
var result4 = dataList.Where(CombineWithOr(filter1, filter2, filter3)); 

Upvotes: 0

Ian H.
Ian H.

Reputation: 3919

You can simply call .Where(filter) for every filter that you want to apply.

You can filter the IEnumerable<T> that .Where() returns again, filtering out all elements that you want.

Usage:

IEnumerable<someType> result = dataList.Where(filter1).Where(filter2).Where(filter3);

What you could do aswell is have all the filtering conditions in a single expression, instead of multiple ones.

Upvotes: 2

Related Questions