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.