【问题标题】:where condition inside nested list linq嵌套列表linq中的条件
【发布时间】:2016-02-10 07:49:43
【问题描述】:

我有两门课

  public class Item
  {
    public string LineID{ get; set; }
    public string ItemNo{ get; set; }
    public List<Itemcode> ItemcodeList{ get; set; }
  }

  public class Itemcode
   {
      public string LineID{ get; set; }
      public string code { get; set; }
      public string codeValue { get; set; }
   }

还有两个数据表 ds.Tables[1] 和 ds.Tables[2]

我正在将两个数据集中的数据转换为 Item 类的列表,其中还包含 Itemcode 类的列表

我的做法如下

 List<Item> items = ds.Tables[1].AsEnumerable().Select(dataRow => new Item
                    {
                        LineID= Convert.ToString(dataRow.Field<int>("LineID")),
                        ItemNo= dataRow.Field<string>("ItemNo"),
                        ItemcodeList = ds.Tables[2].AsEnumerable().Select(row => new Itemcode
                        {
                            code= Convert.ToString(row.Field<string>("code")),
                            codeValue = Convert.ToString(row.Field<string>("codeValue")),
                        }).ToList()
                    }).ToList();

上面的代码针对 ds.Table[1] 的每一行给出了所有 ds.Tables[2] 行

但我只想要 ds.Table[1] 的 LineID 与 ds.Table[2] 的 LineID 匹配的那些行,我必须更改条件

【问题讨论】:

  • 为什么需要 AsEnumerable() ?
  • 因为 DataTable 没有实现 IEnumerable

标签: c# linq lambda


【解决方案1】:

恕我直言,一种更简洁的解决方案(也提高了大型数据集的性能)是首先创建子项的查找,然后组装父项:

        var itemCodes = (
            from dataRow in ds.Tables[2].AsEnumerable()
            select new Itemcode
            {
                LineID = dataRow.Field<string>("LineID"),
                code = dataRow.Field<string>("code"),
                codeValue = dataRow.Field<string>("code")
            }).ToLookup(ic => ic.LineID);

        var lines = (
            from dataRow in ds.Tables[1].AsEnumerable()
            let lineID = dataRow.Field<string>("LineID")
            select new Item
            {
                LineID = lineID,
                ItemNo = dataRow.Field<string>("ItemNo"),
                ItemcodeList = itemCodes[lineID].ToList()
            }).ToList();

或者,如果您更喜欢方法链语法:

        var itemCodes = ds.Tables[2].AsEnumerable().Select(dataRow => new Itemcode
        {
            LineID = dataRow.Field<string>("LineID"),
            code = dataRow.Field<string>("code"),
            codeValue = dataRow.Field<string>("code")
        }).ToLookup(ic => ic.LineID);

        var lines = ds.Tables[1].AsEnumerable()
            .Select(dataRow => new {dataRow, lineID = dataRow.Field<string>("LineID")})
            .Select(item => new Item
            {
                LineID = item.lineID,
                ItemNo = item.dataRow.Field<string>("ItemNo"),
                ItemcodeList = itemCodes[item.lineID].ToList()
            }).ToList();

【讨论】:

  • @Silvermind 数据已经在内存中。并且查找只会保留对其值集合中对象的引用,而不是它们的副本。
【解决方案2】:

我认为在这里使用group join 会是一个很好的解决方案。

var items= (from tbl1 in ds.Tables[1].AsEnumerable()
            join tbl2 in ds.Tables[2].AsEnumerable()
              on tbl1.Field<int>("LineId") equals tbl2.Field<int>("LineID") into g
            select new Item
            {
               LineID = tbl1.Field<int>("LineID").ToString(),
               ItemNo = tbl1.Field<string>("ItemNo"),
               ItemcodeList = g.Select(row => 
                  new Itemcode
                  {
                     code = row.Field<string>("code").ToString(),
                     codeValue = row.Field<string>("codeValue").ToString(),
                  }).ToList()
            }).ToList();

【讨论】:

【解决方案3】:

只需添加 where 子句并将其与数据行中的 LineId 进行比较

List<Item> items = ds.Tables[1].AsEnumerable().Select(dataRow => new Item
                    {
                        LineID= Convert.ToString(dataRow.Field<int>("LineID")),
                        ItemNo= dataRow.Field<string>("ItemNo"),
                        ItemcodeList = ds.Tables[2].AsEnumerable().Where(ic=>ic.Field<int>("LineId")==dataRow.Field<int>("LineID")).Select(row => new Itemcode
                        {
                            code= Convert.ToString(row.Field<string>("code")),
                            codeValue = Convert.ToString(row.Field<string>("codeValue")),
                        }).ToList()
                    }).ToList();

其他信息

这里 AsEnumerable 与 AsQueryable 不同....这里的数据已经从您的数据库中获取并填充到您的 DataSet 的 DataTable 中....您必须执行 AsEnumerable 的原因是因为 DataTable 没有实现 IEnumerable 并且您的所有 Linq 查询仅适用于类型 IEnumerable

【讨论】:

  • ds.Tables[2].AsEnumerable().Where() - 这将获取所有记录并在之后应用条件
  • 你已经在内存中有记录...它会枚举并只选择那些满足条件的记录
  • @Viru 我收到错误 System.Data.DataRow' 不包含 'LineId' 的定义,并且没有扩展方法 'LineId' 接受类型为 'System.Data.DataRow' 的第一个参数Where(ic=>ic.LineId==dataRow.Field
  • 您的解决方案无法编译。在“Where”子句“ic => ic.LineId”中,“ic”的类型为“DataRow”,它没有属性“LineId”
【解决方案4】:

如果你想要 lambda 解决方案,以下应该可以工作:

List<Item> items =
            ds.Tables[0].AsEnumerable().GroupJoin(
            ds.Tables[1].AsEnumerable(),
            tab1 => tab1.Field<int>("LineID"),
            tab2 => tab2.Field<int>("LineID"),
            (tab1, tab2) => new Item
                        {
                            LineID = Convert.ToString(tab1.Field<int>("LineID")),
                            ItemNo = tab1.Field<string>("ItemNo"),
                            ItemcodeList = tab2.AsEnumerable().SelectMany(codes=> 
                                new List<Itemcode>                                   
                                {
                                    new Itemcode { code = codes.Field<string>("Code")} 
                                }
                            ).ToList()
                        }
            ).ToList();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-09
    • 2021-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-18
    相关资源
    最近更新 更多