【问题标题】:Using LINQ to Filter Multi Dimensional Criteria使用 LINQ 过滤多维标准
【发布时间】:2016-01-28 21:38:43
【问题描述】:

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

条件包括“FieldName”和“SearchOperator”,例如:

FieldName 可能包括“FirstName”、“LastName”、“DateOfBirth”等

SearchOperator 可能包括“Equals”、“BeginsWith”、“EndsWith”、“Greater”、 ...等

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

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

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;
            }
    }

【问题讨论】:

    标签: c# entity-framework linq


    【解决方案1】:

    您可以使用动态 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;
    
                        }   
    

    【讨论】:

    • 您能否使用 String.StartsWith、String.Contains 更新您的答案,如果可能,日期大于
    • 您是否测试过您的代码是否正常工作?它告诉我不能将字符串转换为 System.Ling.Expression.Expression>
    • 我喜欢这种方法,但为了使其工作,您必须安装动态库,它会为您的项目添加两个依赖项。这就是为什么我没有选择它作为正确的解决方案。不过谢谢!投票
    • 谢谢。是的,我知道它添加了动态 Linq 依赖项,但如果你动态地做 linq 事情,这是必需的。
    【解决方案2】:

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

           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));
            }
    

    所以如果你需要它是可以扩展的。

    【讨论】:

      【解决方案3】:

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

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

      否则你可以尝试构建表达式树。看这里:Expression.Lambda and query generation at runtime, simplest "Where" example

      例如:

      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);
      

      (我没有测试代码,它可能有错误,但我相信它应该或多或少像这样) 基本上,它更有效,因为 Entity Framework 正在通过遍历 Expression> 将您的查询转换为 SQL 查询。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-06-26
        • 1970-01-01
        • 2013-05-26
        • 2016-01-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多