使用 LINQ 筛选多维条件

本文关键字:条件 筛选 LINQ 使用 | 更新日期: 2023-09-27 18:32:18

我正在尝试使用 LINQ 构建搜索查询,以利用用户传递的条件将其传递给实体框架。标准是二维的。

条件包括"字段名称"和"搜索运算符",例如:

字段名称可能包括"名字"、"姓氏"、"出生日期"、...等

搜索运算符可能包括"等于"、"开始为"、"结束于"、"更大"、...等

如您所见,有太多条件需要处理。实现代码的最佳方法是什么?

我当前的代码看起来像这样,但我觉得应该有更好的方法来做到这一点。

IQueryable<Employee> query = dbContext.Employee;
    switch (FieldName)
    {
        case "FirstName":
            switch (SearchOperator)
            {
                case "Equals":
                    query = query.Where(x => x.FirstName.Equals(SearchValue));
                    break;
                case "BeginsWith":
                    query = query.Where(x => x.FirstName.StartsWith(SearchValue));
                    break;
            }
            break;
        case "LastName":
            switch (SearchOperator)
            {
                case "Equals":
                    query = query.Where(x => x.LastName.Equals(SearchValue));
                    break;
                case "BeginsWith":
                    query = query.Where(x => x.LastName.StartsWith(SearchValue));
                    break;
            }
    }

使用 LINQ 筛选多维条件

您可以使用动态 linq:

查看文章:

http://weblogs.asp.net/scottgu/dynamic-linq-part-1-using-the-linq-dynamic-query-library。

使用动态 LINQ 可以执行以下操作:

switch (SearchOperator)
                    {
                        case "Equals":
                            query = query.Where(String.Format("{0}={1}",FieldName,SearchValue));
                            break;
                        case "Contains":
                            query = query.Where(String.Format("{0}.Contains({1})",FieldName,arrayOfSearchValues));
                        break;
                        case "StartsWith":
                            query = query.Where(String.Format("{0}.StartsWith({1})",FieldName,SearchValue));
                        break;
                      case "Greater":
                          query = query.Where(String.Format("{0}>{1}",FieldName,SearchValue));
                            break;
                    }   

您可以在字典中保持动态过滤:

       IQueryable<Employee> query = dbContext.Employee;
        Dictionary<Tuple<string, string>, Func<Employee, string, bool>> _filter = new Dictionary<Tuple<string, string>, Func<Employee, string, bool>>()
        {
           { new Tuple<string, string>("FirstName","Equals"),   (x,s) => x.FirstName.Equals(s)},
            { new Tuple<string, string>("FirstName","BeginsWith"),   (x,s) => x.FirstName.StartsWith(s)},
             { new Tuple<string, string>("LastName","Equals"),   (x,s) => x.LastName.Equals(s)},
              { new Tuple<string, string>("LastName","BeginsWith"),   (x,s) => x.LastName.StartsWith(s)},
        }; 

        public Employee Get()
        {
             Func<Employee, string, bool> filter = _filter.FirstOrDefault(k => k.Key.Item1 == FieldName && k.Key.Item2 == SearchOperator).Value;
            return query.FirstOrDefault(e => filter(e, SearchValue));
        }

因此,如果需要,它是可扩展的。

如果你不需要高性能或者你的数据库很小,你可以使用 IEnumerable 来链接 where 语句,如下所示:

IEnumerable<Employee> query = dbContext.Employee;
foreach(var searchOperator in searchOperators)
{
     query = query.Where(n=> ....); 
}

否则,您可以尝试构建表达式树。看看这里: Expression.Lambda 和运行时的查询生成,最简单的"Where"示例

例如:

var employee = Expression.Parameter(typeof(Employee), "employee");
var exprList = new List<BinaryExpression>();
foreach(var searchOperator in searchOperators)
{
  switch(FieldName)
  {
      case "FirstName":
      {   
         var property = Expression.Property(item, "FirstName");
         switch(SearchOperator)
         {
             case "Equal":
                 var equalTo = Expression.Constant(SearchFirstName);
                 var expr = Expression.Equal(property, equalTo);
                 exprList.Add(expr);
                 break;
             case "StartWith":
                 ....
         }

         break;
      }
  }
}
var combined = exprList.Aggregate((n,m)=> Expression.And(n,m));
Expression<Func<Employee, bool>> expr = Expression.Lambda<Func<Item, bool>>(combined, employee);
var output = dbContext.Employee.Where(expr);

(我没有测试代码,它可能有错误,但我相信它应该或多或少看起来像这样)基本上,它更有效,因为实体框架通过遍历 Expression> 将查询转换为 SQL 查询。