问题描述
如何基于应该在where子句中的或
操作使用的一组过滤器或表达式来过滤数据?
How is it possible to filter data based on some set of filters or expressions that should be used with or
operation in where clause?
例如,有一个类:
class DTOFilter
{
public string Domain { get; set; }
public string Mobile { get; set; }
}
必须过滤 Users
列表基于下一步的过滤器列表:
It is required to filter Users
list based on the list of the filters next way:
u=>
(u.Email.Contains(filters[0].Domain) && u.PhoneNumber.StartsWith(filters[0].Mobile)) ||
(u.Email.Contains(filters[1].Domain) && u.PhoneNumber.StartsWith(filters[1].Mobile)) ||
...
显然,应该以如下形式自动构建:
Obviously that should be build automaticaly in form like:
db.Users.Where(filters.Filter<Users, DTOFilter>(
(u, f) => u.Email.Contains(f.Domain)
&& u.PhoneNumber.StartsWith(f.Mobile))
.Or())
推荐答案
要执行该任务,需要实现两个功能:
To perform that task it's required to implement two functions:
-
或
表达式联接函数 - 过滤数据拆分函数
Or
expression join function- Filter data split function
Or函数遍历表达式的集合,并将它们加入 Or
表达式中,例如((( expression1或expression2)或expression3)或expression4)
Or function goes through a collection of expressions and joins them in a Or
expression like (((expression1 or expression2) or expression3) or expression4)
public static Expression<Func<T, bool>> Or<T>(
this IEnumerable<Expression<Func<T, bool>>> source)
{
var expressions = source.ToList();
if (expressions.Count == 0)
return x => false;
var orExpression = expressions
.Select(e => e.Body)
.Aggregate((a, b) => Expression.OrElse(a, b));
var parameter = expressions.First().Parameters.First();
return Expression.Lambda<Func<T, bool>>(orExpression, parameter);
}
如果过滤器已经是有效的表达式,则该功能已经可以使用。
This function can already be used if filters are already valid expressions.
过滤拆分数据函数,应将选择器表达式乘以并用精确的对象值替换结果表达式参数。在函数中完成过滤数据填充:
Filter split data function, should multiply the selector expression and replace in the result expression parameter with the exact object value. Filter data population is done in the function:
public static IEnumerable<Expression<Func<T, bool>>> Filter<T, TData>(
this IEnumerable<TData> data,
Expression<Func<T,TData, bool>> selector)
{
var parameter = selector.Parameters.First(p => p.Type.IsAssignableFrom(typeof(T)));
return data.Select(item => Expression.Lambda<Func<T, bool>>(
new DataVisitor<TData>(item).Visit(selector.Body), parameter));
}
下一个访问者实现有助于用确切的值替换参数:
Next visitor implementation helps to replace parameter with the exact value:
public class DataVisitor<T> : ExpressionVisitor
{
private readonly ConstantExpression _data;
public DataVisitor(T dataItem)
{
_data = Expression.Constant(dataItem);
}
protected override Expression VisitParameter(ParameterExpression node)
{
return node.Type.IsAssignableFrom(typeof(T))
? _data : base.VisitParameter(node);
}
}
build表达式是正确的lambda表达式,可以是由EF表达式树解析器解析。
The build expression is a correct lambda expression that can be parsed by the EF expression tree parser.
这篇关于过滤具有多个复杂子句的数据,这些子句与where函数中的OR操作结合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!