.NET Framework 3.5になって、DataTableに以下の拡張メソッドが用意されました。
- AsDataView
- AsEnumerable
- CopyToDataTable
尚、これらの拡張メソッドは、System.Data.DataTableExtensionsクラスに定義されています。
厳密にはCopyToDataTableメソッドはIEnumerable系の拡張メソッドなんですが、DataTableと
合わせて利用するのでここに挙げてます。
AsEnumerableメソッドを利用するとDataTableにLinqを実行することが出来ます。
例:
IEnumerable<DataRow> query = from row in table.AsEnumerable()
where 条件
select row;
みたいな感じです。
で、現実的によく行うのが抽出した結果をまた別のDataTableとして
利用するというパターンです。
その場合に、CopyToDataTableメソッドが利用できます。
CopyToDataTableメソッドのメソッドシグネチャは以下のようになっています。
DataTable CopyToDataTable<T>(this IEnumerable<T> source) where T : DataRow
つまり、TにはDataRowかそのサブクラスしか許容されません。
AsEnumerableが返却するのはIEnumerable
その結果のクエリはそのままCopyToDataTableがコールできるようになってます。
DataTable newTable = query.CopyToDataTable();
これで、新しいデータテーブルの出来上がりです。
以下そのサンプルです。
#region DataTableExtensionsSample-01 public class DataTableExtensionsSample01 : IExecutable{ public void Execute(){ DataTable table = BuildSampleTable(); PrintTable("Before:", table); IEnumerable<DataRow> query = from row in table.AsEnumerable() where (row.Field<int>("COL-1") % 2) != 0 select row; DataTable newTable = query.CopyToDataTable(); PrintTable("After:", newTable); } DataTable BuildSampleTable(){ DataTable table = new DataTable(); table.BeginInit(); table.Columns.Add("COL-1", typeof(int)); table.Columns.Add("COL-2"); table.EndInit(); table.BeginLoadData(); for(int i = 0; i < 5; i++){ table.LoadDataRow(new object[]{i, (i + 1).ToString()}, true); } table.EndLoadData(); return table; } void PrintTable(string title, DataTable table){ Console.WriteLine(title); foreach(DataRow row in table.Rows){ Console.WriteLine("\t{0}, {1}", row[0], row[1]); } Console.WriteLine(); } } #endregion
補足:ちなみに、AsEnumerableを使わない場合でも
from DataRow row in table.Rows
where 条件
select row;
って書き方でもいけます。どちらを使うかは個人の好みですね。
from row in table.Rows
という書き方はエラーとなります。Rowsが返すDataRowCollectionがIEnumerable
実装していないからです。