【问题标题】:How to build a Linq Query Dynamically如何动态构建 Linq 查询
【发布时间】:2013-01-16 04:44:30
【问题描述】:

我看过一些旧帖子,但不知道如何实现这一点,请举个例子。

我正在对 DataTable 运行查询以对所有列进行分组。数字列只会被称为运行时,因此我需要动态构建查询。

var newGroup = from row in dataTable.AsEnumerable() 
group row by new { ID = row.Field<string>("column1"), group1 = row.Field<string>("column2") };

我需要为n number of columns 动态构建上述查询。

请解释如何通过遍历列列表并构建 Lambda 表达式来构建 ParameterExpression。

【问题讨论】:

  • 您能就我的回答提供反馈吗?我认为它应该足以回答或引导您找到所需的解决方案。

标签: c# .net linq


【解决方案1】:

简而言之:有不同的方法可以实现这一目标。困难的方法是通过使用表达式来构建 Func 和 Predicates 的组合。更简单的方法是使用库 - LINQ Dynamic Query Library 下面提到:

解决方案 #1: 这是一个很好的起点 - Building LINQ Queries at Runtime in C#

解决方案 #2:您也应该能够使用 Linq Dynamic Query 来执行此操作,因为它是为此目的而构建的 - Dynamic LINQ (Part 1: Using the LINQ Dynamic Query Library)

【讨论】:

    【解决方案2】:

    我已经多次看到这个问题,所以我决定创建一个博客,而不是从 C# 中处理数据。我通过使用动态 SQL 完成了 SQL 数据库级别的繁重工作。

    Here is the link。希望这会有所帮助。

    【讨论】:

      【解决方案3】:

      我遇到过需要为查询的左侧和右侧动态生成 LINQ 查询的情况。换句话说,Where("some property == some value")。我从 LINQPad 的人那里玩过 PredicateBuilder,并尝试了其他一些东西,但最终 LINQ 动态查询库 (System.Linq.Dynamic) 使这项任务变得非常简单。

      在不详述所有细节的情况下,我所拥有的是一种方法,它采用参数来过滤和排序 MVC 页面上 jqGrid 上的项目。一个名为 QueryOptions 的对象包含各种查询设置。 Data.ImportDataSearchView 是绑定到后端数据库视图的实体框架实体。

      过滤器表达式是通过调用建立的:

              options.FilterExpression += filterList.BuildFilterExpression<Data.ImportDataSearchView>();
      

      BuildFilterExpression部分如下:

          public string BuildFilterExpression<T>()
          {
              var type = typeof(T);
              var exp = string.Empty;
      
              foreach (Filter filter in this)
              {
                  var typeName = filter.DataType.ToLower();
      
                  // Skip if no values
                  if (!filter.Values.Any())
                      continue;
      
                  switch (typeName)
                  {
                      case "string":
                          // html decode string and escape single quotes
                          var stringVal = System.Web.HttpUtility.HtmlDecode(filter.Values[0]);
                          stringVal = stringVal.Replace("'", "''");
      
                          if (filter.Operator == Enums.FilterOperator.CONTAINS)
                              exp += string.Format("{0}.Trim().ToLower().Contains(\"{1}\")", filter.Attribute, stringVal.Trim().ToLower());
      
                          else if (filter.Operator == Enums.FilterOperator.DOES_NOT_EQUAL)
                              exp += string.Format("!{0}.ToLower().Equals(\"{1}\")", filter.Attribute, stringVal.ToLower());
      
                          else if (filter.Operator == Enums.FilterOperator.DOES_NOT_CONTAIN)
                              exp += string.Format("!{0}.Trim().ToLower().Contains(\"{1}\")", filter.Attribute, stringVal.Trim().ToLower());
      
                          else if (filter.Operator == Enums.FilterOperator.ENDS_WITH)
                              exp += string.Format("{0}.Trim().ToLower().EndsWith(\"{1}\")", filter.Attribute, stringVal.Trim().ToLower());
      
                          else if (filter.Operator == Enums.FilterOperator.EQUALS)
                              exp += string.Format("{0}.ToLower().Equals(\"{1}\")", filter.Attribute, stringVal.ToLower());
      
                          else if (filter.Operator == Enums.FilterOperator.STARTS_WITH)
                              exp += string.Format("{0}.Trim().ToLower().StartsWith(\"{1}\")", filter.Attribute, stringVal.Trim().ToLower());
      
                          break;
      
                      //case "select": -- for dropdowns
                      //case "datetime": -- for dates, etc. etc.
      
                  // add spaces around expression
                  exp = string.Format(" {0} ", exp);
      
                  // add and/or to expression
                  if (this.IndexOf(filter) != this.Count() - 1)
                      exp += string.Format(" {0} ", ExpressionType.ToLower() == "and" ? "&&" : "||");
              }
      
              return exp;
          }
      

      然后在建立表达式字符串后,如下检索数据:

              options.OrderBy = string.IsNullOrEmpty(sortIndex) ? "TrackingId asc" : string.Format(" {0} {1} ", sortIndex, sortOrder);
      
              var db = new Data.BmpDB();
              var list = string.IsNullOrEmpty(options.FilterExpression)
                  ? db.ImportDataSearchViews.OrderBy(options.OrderBy).ToList()
                  : db.ImportDataSearchViews.Where(options.FilterExpression).OrderBy(options.OrderBy).ToList();
      

      下面的 options.FilterExpression 字符串是三个搜索条件字段的示例,这些字段由 BuildFilterExpression 方法拼凑成一个漂亮、简单的 LINQ where 子句谓词字符串:

      "BmpName.Trim().ToLower().Contains(\"crops\") && DataProviderId.ToLower().Equals(\"123\") && StatusId == 1"

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多