【问题标题】:using dynamic linq to filter a list of objects使用动态 linq 过滤对象列表
【发布时间】:2017-06-05 22:33:14
【问题描述】:

我有两个这样的班级

public class Error{
   public string Code{get;set;}
   public string Description{get;set;}
}

public class Row{
   public List<Error> Errors {get;set;}
   ....
}

因此,对于每一行,可以存在更多错误。 是否可以使用动态 linq 选择具有错误代码的行(例如 Code1)?

所以,如果该行包含 Code1 和 Code2,我想选择该行。

如果在下面的示例中查询有一个行列表,我想要这样的查询

query.Where("Errors != null && Errors.Code.contains('Code1')")

【问题讨论】:

  • 您的查询中真正的 dynamic 是什么?
  • 这个例子不是动态的,我有一个表格,用户可以从代码列表中选择
  • 那么为什么需要dynamic-linq,它与基于字符串的SelectWhereOrderBy等查询相关联的System.Linq.Dynamic包?

标签: c# linq dynamic-linq


【解决方案1】:

是否可以使用动态 linq 选择有错误代码的行(例如 Code1)?

按照我的理解,你有这样的东西

IQueryable<Row> query = ...;
string code = "Code1";

并且您想要以下静态查询的动态 LINQ 等效项:

var result = query
   .Where(row => row.Errors != null && row.Errors.Any(error => error.Code == code));

由于在动态 LINQ 中,每个 Enumerable 扩展方法 lambda 都会进入一个单独的“范围”,因此可以通过特殊的 it 标识符或根本没有标识符来访问其中的成员。它还允许您传递参数并使用@p0@p1 等按索引在查询字符串中引用它们。

因此,上述等效的动态 LINQ 查询可能是这样的:

var result = query
    .Where("Errors != null && Errors.Any(Code == @0)", code);

如果您想要string.Contains 而不是完全匹配,只需将Code == @0 替换为Code.Contains(@p0)

当然你可以将字符串字面值嵌入其中,但请注意它需要用双引号括起来 ("):

var result = query
    .Where("Errors != null && Errors.Any(Code == \"Code1\")");

【讨论】:

    【解决方案2】:

    我想这就是你要找的:

    var codes=new List<string>{"Code1","Code2"}; 
    // given a list of codes you want those rows that contains all codes
    var result= rows.Where(r=> codes.All(c=>r.Errors.Any(e=>e.Code==c)));
    

    为了避免错误列表的null检查,我建议你在一个空的构造函数中初始化列表:

    public Row()
    {
       Errors=new List<Error>();
    }
    

    【讨论】:

    • 感谢您的回复,我想使用动态 linq,而不是 linq。
    • @user3401335 为什么你更关心使用的工具,而不是结果?
    • 因为我在表(jqgrid)中有二十个过滤器,所以我想使用动态linq来查询表而不在代码中写入条件
    【解决方案3】:
    IEnumerable<Row> rowCollection = ...; //your rows
    var result = rowCollection
        .Where(r => r.Code.Contains("Code1") && r.Code.Contains("Code2"))
        .ToList();
    

    【讨论】:

      【解决方案4】:

      使用 linq 的 where 扩展方法。并检查代码是否等于 Code1 或 Code2 并将结果转换为错误列表

       List<Error> rows = row.Errors
                  .Where(x => x.Code == "Code1" && x.Code == "Code2")
                  .ToList();
      

      var result = (from x in row.Errors
                  where x.Code == "Code1" && x.Code == "Code2"
                  select x).ToList();
      

      【讨论】:

      • 这是一个和 (&&),我认为 OP 不想做那种硬编码,而且不是我投反对票,我不喜欢这样做
      【解决方案5】:

      您真正想做的是使用 PredicateBuilder 之类的东西: http://www.albahari.com/nutshell/predicatebuilder.aspx

      IQueryable<Error> SearchProducts(Row row, string[] codes, string[] keywords)
      {
          var predicate = PredicateBuilder.False<Error>();
      
          foreach (string code  in codes)
          {
              string temp = code;
              predicate = predicate.Or(p => p.Code.Contains(temp));
          }
          foreach (string keyword in keywords)
          {
              string temp = keyword;
              predicate = predicate.Or(p => p.Description.Contains(temp));
          }
          return row.Errors.AsQueryable().Where(predicate);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-06
        • 1970-01-01
        • 1970-01-01
        • 2021-12-05
        • 2022-01-16
        相关资源
        最近更新 更多