过滤具有多个复杂子句的数据

过滤具有多个复杂子句的数据

本文介绍了过滤具有多个复杂子句的数据,这些子句与where函数中的OR操作结合的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何基于应该在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:


  1. 表达式联接函数

  2. 过滤数据拆分函数

  1. Or expression join function
  2. 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操作结合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-20 04:40