Home > other >  How to combine multiple condition expressions in .Net Core EF to filter data?
How to combine multiple condition expressions in .Net Core EF to filter data?

Time:05-03

I am using the below code to filter records based on dynamic column names

string[] colNames = {"firstName", "lastName", "Col3", "col4"}
string[] colValues = {"jac", "sam", "col3value","col4value"}

ParameterExpression param = Expression.Parameter(typeof(Student), "t");
MemberExpression column = Expression.Property(param, colNames[0]);
ConstantExpression searchValue = Expression.Constant(colValues[0]);
MethodInfo containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
Expression exp = Expression.Call(column, containsMethod, searchValue);
var deleg = Expression.Lambda<Func<Student, bool>>(exp, param).Compile();

var students = context.StudentModel.Where(deleg).AsQueryable();

How do i do this for multiple columns (combining all the columns in array in my case)

CodePudding user response:

ParameterExpression param = Expression.Parameter(typeof(Student), "t");
Expression groupExp = null;

foreach (PageFilter filter in query.PageFilters)
{
                
    Expression con;
    MethodInfo containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
    con = Expression.Call(Expression.Property(param, filter.Name), containsMethod, Expression.Constant(filter.Value));
    groupExp = groupExp == null ? con : Expression.AndAlso(groupExp, con);

}

var deleg = Expression.Lambda<Func<Student, bool>>(groupExp, param);

var students = context.StudentModel.Where(deleg).AsQueryable();

This worked for me.

CodePudding user response:

The basic approach, in this case, is to create many Expression.Call and combine these calls with Expression.AndAlso as was suggested by Svyatoslav Danyliv.

They must share the same parameter.

So the solution will be following:

ParameterExpression param = Expression.Parameter(typeof(Student), "s");
MethodInfo containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });

Expression combinedExpression = null; // this will be passed to context.StudentModel.Where

for (int i = 0; i < colNames.Length; i  )
{
    MemberExpression column = Expression.Property(param, colNames[i]);
    ConstantExpression searchValue = Expression.Constant(colValues[i]);

    Expression expression = Expression.Call(column, containsMethod, searchValue);

    combinedExpression = combinedExpression == null
        ? expression;
        : Expression.AndAlso(combinedExpression, expression);
}

You don't need to compile combinedExpression, as .Where requests Expression<Func<...>>, not Func itself.

`var students = context.StudentModel.Where(combinedExpression);

To get all the filters to work correctly I assume you need to create separate expressions for different types e.g. int, int? to check them for equality as well (or >, => etc.). Because current Contains usage is very limited.

P.S. make sure you have correct property names in colNames array, otherwise you'll get an error at Expression.Property call.

  • Related