web-dev-qa-db-ja.com

ASP.NET Core 2.0でDataTableをIEnumerable <T>に変換する

別のシステムから入力として受け取ったDataTableから 'IEnumerableを生成する必要があります。次のコードは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」を生成する最も効率的な方法は何ですか?

11
Roddy Balkan

実行できる最も効率的な方法の1つは、LINQの代わりにforループを使用して、DataTableの行を繰り返し処理し、IEnumerable<UserAssignmentDto>メソッドは値を「手で」返します。

DataTableは.NET Core 2.0のEnumeratorを実装していないため、「通常の」forループを使用して行を反復処理する必要があります。 DataTableは.NET Core 2.0でIEnumerableを実装していないため、foreachは使用できません。

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;
}
3
Brian Ogden

以下は、古典的なAsEnumerable()が実行したことを模倣して、DataTableからDataRowsのEnumerableコレクションを返す汎用のAsEnumerable拡張機能です。コードを.netコアに移植するときに必要なリファクタリングの量を最小限に抑えたい場合に役立ちます。

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

最も効率的ではありませんが、別の方法として、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();
}
6
Naser Yousefi

.net core 2の正しいnugetパッケージはSystem.Data.DataSetExtensions

4

AsEnumerable()は.NET Core 2.0に存在します。同様の質問への回答に記載されているように、System.Data.DataExtensionsへの参照を追加するだけです。 LINQ to DataSet、DataTable.AsEnumerable()が認識されない

3
r2k83

効率はユースケースに依存します。結果全体が必要な場合、ブリアンズの答えは良いです。 Listの容量を事前に割り当てて、サイズ変更や配列への変更を回避することで改善できますが、一般的には良好です。 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;
            }
        }
1
Antonín Lejsek

myDataTable.Select();を使用して、すべてのDataRowの配列を返します。

0
Nitika Chopra