【问题标题】:Convert DataTable to IEnumerable<T> in ASP.NET Core 2.0在 ASP.NET Core 2.0 中将 DataTable 转换为 IEnumerable<T>
【发布时间】:2018-02-04 15:47:43
【问题描述】:

我需要从一个 DataTable 中生成一个 'IEnumerable,该 DataTable 作为来自另一个系统的输入。以下代码在 ASP.NET 4.6.1 中工作。

public static IEnumerable<UserAssignmentDto> StaffAssignmentsUsingStoredProcedure(System.Data.DataTable dataTable)
    {
        var data = dataTable.AsEnumerable().Select(row =>
            new UserAssignmentDto
            {
                Id = ((string)row["AssignmentNumber"]),
                Position = (string) row["EsrPositionTitle"],

            });

        return data;
    }

但是,在 ASP.NET Core 2.0 中,“DataTable”不再包含“AsEnumerable”的定义。

生成我需要的“IEnumerable”的最有效方法是什么?

【问题讨论】:

  • 使用 for 循环并遍历 DataTable 行并水合 IEnumerable
  • 你能告诉我你所说的水合物是什么意思吗?
  • 你不能直接说dataTable.Rows.Select(...); 吗?如果选择“项目”是一个对象,你可以添加 OfType dataTable.Rows.OfType&lt;DataRow&gt;().Select(...);
  • 您也可以使用演员表:dataTable.Rows.Cast&lt;DataRow&gt;().Select(...)。这比 OfType 好还是坏?

标签: c# asp.net linq asp.net-core


【解决方案1】:

.net core 2 的正确 nuget 包是 System.Data.DataSetExtensions

【讨论】:

  • 这个nuget是后面介绍的;但真的很有帮助,因为我们可以像 .net 框架一样使用。 :)
【解决方案2】:

这是一个通用的 AsEnumerable 扩展函数,用于模仿经典的 AsEnumerable() 所做的,从 DataTable 返回 DataRows 的 Enumerable 集合。对于希望将代码移植到 .net 核心时所需的重构量最小化的人来说可能很有用。

    public static IEnumerable<DataRow> AsEnumerable(this DataTable table)
    {
        for (int i = 0; i < table.Rows.Count; i++)
        {
            yield return table.Rows[i];
        }
    }

【讨论】:

    【解决方案3】:

    不是最有效的,但作为替代方案,您可以使用Select 方法:

    DataRow[] rows= dataTable.Select();
    

    现在你有一个 IEnumerable 行。 此方法可能对某人有所帮助:

    public static List<T> ConvertDataTableToGenericList<T>(DataTable dt)
    {
         var columnNames = dt.Columns.Cast<DataColumn>()
                .Select(c => c.ColumnName)
                .ToList();
    
         var properties = typeof(T).GetProperties();
         DataRow[] rows= dt.Select();
         return rows.Select(row =>
         {
              var objT = Activator.CreateInstance<T>();
              foreach (var pro in properties)
              {
                  if (columnNames.Contains(pro.Name))
                       pro.SetValue(objT, row[pro.Name]);
              }
    
              return objT;
         }).ToList();
    }
    

    【讨论】:

      【解决方案4】:

      您可以做的最有效的事情之一是自己编写迭代代码,使用 for 循环而不是 LINQ,只需迭代 DataTable 行并“手动”构建/水合 IEnumerable&lt;UserAssignmentDto&gt; 方法返回值.

      由于 DataTable 没有在 .NET Core 2.0 中实现 Enumerator,因此您需要使用“常规”for 循环来迭代行。您不能使用 foreach,因为 DataTable 尚未在 .NET Core 2.0 中实现 IEnumerable。

      public static IEnumerable<UserAssignmentDto> StaffAssignmentsUsingStoredProcedure(System.Data.DataTable dataTable)
      {
          var retList = new List<UserAssignmentDto>();
      
          for(int i = 0; i < dataTable.Rows.Count; i++)
          {
                var row = dataTable.Rows[i];
      
                var temp = new UserAssignmentDto(){
                    Id = row["AssignmentNumber"],
                    Position = row["EsrPositionTitle"]
                };
      
                retList.Add(temp);     
          }
      
          return retList;
      }
      

      【讨论】:

      • 我认为 List 需要初始化。此外,我收到错误 CS1579 foreach 语句无法对“DataTable”类型的变量进行操作,因为“DataTable”不包含“GetEnumerator”的公共定义
      • @RoddyBalkan 好的,我更新了答案以修复该错误
      • @RoddyBalkan List 已经初始化,这行代码: var retList = List();
      • @RoddyBalkan 对不起,我忘记了初始化 List 的新关键字,请注意,您不能使用 foreach,因为 DataTable 在 .NET Core 2.0 中没有实现 GetEnumerator
      【解决方案5】:

      AsEnumerable() 确实存在于 .NET Core 2.0 中,您只需添加对 System.Data.DataExtensions 的引用,如类似问题的答案中所述。 LINQ to DataSet, DataTable.AsEnumerable() not recognized

      【讨论】:

        【解决方案6】:

        效率取决于用例。如果您需要整个结果,Brians 的回答很好。可以通过预先分配 List 的容量以避免调整大小或更改为 Array 来改进它,但通常它是好的。我宁愿返回 List 或 Array 以更明确地展示它的作用,但这是我个人的选择。它在调用它的那一刻保存 DataTable 的状态,这可能是好是坏取决于您的需要。

        如果您可能不需要所有项目,或者您根本不会枚举 IEnumerable,那么构造真正的枚举器可能更有效:

        public static IEnumerable<UserAssignmentDto> StaffAssignmentsUsingStoredProcedure(System.Data.DataTable dataTable)
                {
                    foreach (DataRow row in dataTable)
                    {
                       yield return new UserAssignmentDto()
                        {
                            Id = row["AssignmentNumber"],
                            Position = row["EsrPositionTitle"]
                        };               
                    }
                }
        

        但这仍然不是最快的选择。您可以避免每次屈服时分配新对象。您每次都可以返回相同的对象,只需相应地设置属性。它有一个明显的缺点,即您无法存储此类 IEnumerable 中的对象以供将来使用,但有时您不需要这样做。

        public static IEnumerable<UserAssignmentDto> StaffAssignmentsUsingStoredProcedure(System.Data.DataTable dataTable)
                {
                    UserAssignmentDto ret = new UserAssignmentDto();
                    foreach (DataRow row in dataTable)
                    {
                        ret.Id = row["AssignmentNumber"];
                        ret.Position = row["EsrPositionTitle"];
                        yield return ret;
                    }
                }
        

        【讨论】:

          【解决方案7】:

          你可以使用myDataTable.Select();它返回一个包含所有DataRow的数组

          【讨论】:

            猜你喜欢
            • 2011-03-24
            • 1970-01-01
            • 1970-01-01
            • 2011-09-30
            • 1970-01-01
            • 1970-01-01
            • 2012-02-24
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多