【C#】DataTableとListの変換について

概要

リフレクションを使用し、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.
タイトルとURLをコピーしました