概要
リフレクションを使用し、DataTable型 ⇔ List型の変換を行います。
変換クラスはチェーンで呼び出せるように、拡張メソッドとして実装しています。
環境
- Windows10
- .Net6
準備
エンティティクラスの定義
public class Item
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
サンプルデータの作成
static void Main(string[] args)
{
DataTable targetTable = new DataTable();
targetTable.Columns.Add("id", typeof(int));
targetTable.Columns.Add("name", typeof(string));
targetTable.Columns.Add("price", typeof(string));
for (int i = 0; i < 10; i++)
{
DataRow row = targetTable.NewRow();
row["id"] = i + 1;
row["name"] = $"Item{i}番";
row["price"] = (i * 1000).ToString("#,##0");
targetTable.Rows.Add(row);
}
// DataTable -> List
var list = targetTable.ToList<Item>();
// List -> DataTable
var table2 = list.ToDataTable<Item>();
Console.ReadLine();
}
DataTable → List
public static IList<T> ToList<T>(this DataTable table)
{
var list = new List<T>();
foreach (DataRow row in table.Rows)
{
var item = Activator.CreateInstance<T>();
typeof(T).GetProperties().ToList().ForEach(
//エンティティクラスの情報から型変換を行う(ex.カンマ付き文字列 -> Decimal)
//p => p.SetValue(item, row[p.Name], p.PropertyType, null)
p => p.SetValue(item, Convert.ChangeType(row[p.Name], p.PropertyType), null)
);
list.Add(item);
}
return list;
}
List → DataTable
/// <summary>
/// List内のNullデータは考慮しない
/// </summary>
public static DataTable ToDataTable<T>(this IList<T> list)
{
var table = new DataTable();
typeof(T).GetProperties().ToList().ForEach(
p => table.Columns.Add(p.Name, p.PropertyType)
);
foreach (var item in list)
{
DataRow row = table.NewRow();
typeof(T).GetProperties().ToList().ForEach(
p => row[p.Name] = p.GetValue(item, null)
);
table.Rows.Add(row);
}
return table;
}
List内にnullがあった場合どうするの?と言われた気がしたので、List内のnullデータをDBNullとして登録するパターンも作成します。
/// <summary>
/// List内のNullデータをDBNull.Valueとして登録する
/// </summary>
public static DataTable ToDataTable2<T>(this IList<T> list)
{
var table = new DataTable();
typeof(T).GetProperties().ToList().ForEach(
p => table.Columns.Add(p.Name,
Nullable.GetUnderlyingType(p.PropertyType) ?? p.PropertyType)
);
foreach (var item in list)
{
DataRow row = table.NewRow();
typeof(T).GetProperties().ToList().ForEach(
p => row[p.Name] = p.GetValue(item) ?? DBNull.Value
);
table.Rows.Add(row);
}
return table;
}
関連記事
データの列順序の保証や、取捨選択を行いたい場合は、こちらの記事をご覧ください。
参考資料
Type.GetProperties メソッド (System)
現在の Type のプロパティを取得します。
how to solve this: DataSet does not support System.Nullable.