一覧形式のデータを扱う際、最も便利なDataTableクラスについての解説と、基本的な使い方について解説したいと思います。
DataTableは表形式のデータを扱うクラス
行と列で構成された一覧形式のデータ形式を管理するためのクラスがDataTableです。
特長として
- データベースからのデータ読み込み、データベースへのデータ書き込みが簡単に行える
- DataTable内に保持されているデータは、XML形式のテキストファイルとして保存、及び読み込みができる。
- DataGridViewと関連づける事で、DataTable内に保持されているデータを表示したり、DataGridViewの操作による変更内容を、自動でDataTableに反映してくれる。
- 表示内容のフィルタリング機能を持っており、指定した条件に合うデータだけを絞り込むことが出来る。
- DataTableにデータ(行)を登録した時点で、自動的にオリジナルの値が別領域に保持されるので、変更・追加・削除した内容を元に戻すことが可能。
- 各セルごとにオリジナルと現在の値、その他管理用情報等を保持しているため、メモリ消費量が元のデータの2倍以上必要になる。
といった事が挙げられます。
メモリの消費量は大きいが、便利な機能が豊富であるため、一覧形式のデータを扱うクラスとして重宝されています。
さて、このDataTableは、DataRowとDataColumnという2つのクラスの集合体になっていますので、DataTableを理解するには、この2つのクラスを理解しておく必要があります。
DataRowとDataColumnクラス
一覧表の行を保持するクラスとして、DataRowが用意されています。
また、セルを保持するクラスとして、DataColumnが用意されています。
DataRowとDataColumnの関係は下図の様になっており、1つのDataRowクラスの中に複数のDataColumnが格納されています。
Rowsプロパティ
DataTableクラスは、複数のDataRowを一まとめに管理するクラスです。
DataTableのプロパティにRowsというのがあり、ここに複数のDataRowを保持する構造になっています。
このRowsプロパティには、DataRowCollectionというクラスが入っていて、実際にはDataRowCollectionクラスが複数のDataRowを管理しています。
これを図で表すと以下のようになります。
1つ1つのDataRowクラスには、複数のDataColumnクラスが配列の様に格納されていて、これをDataTableが束ねてしているというイメージです。
Columnsプロパティ
DataRowCollectionが複数のDataRowを管理していると言いましたが、DataTableはColumns プロパティで列の情報、すなわちDataColumnを管理しています。
そしてRowsプロパティと同様に、ColumnsプロパティにはDataColumnCollectionが格納されており、このDataColumnCollectionが複数のDataColumnの情報を管理する構造になっています。
Column.AddとRows.Add
DataTableは、あらかじめ列を追加してから、行を追加していくという手順が必要になります。
まず、最初に new DatatTable() で空のクラスを作成してから、DataTableのColumnsプロパティに対して、Addメソッドで列を追加します。
下記は4つの列を追加するサンプルソースです。
DataTable dt = new DataTable();
dt.Columns.Add("カテゴリ");
dt.Columns.Add("アプリ");
dt.Columns.Add("ID");
dt.Columns.Add("パスワード");
Addメソッドには第2引数があって、変数の型を指定できます。
特に何も指定しなければ、何でも入るobject型が自動的に採用されます。
では、次に行を追加しましょう。
Rowsプロパティに対して、Addメソッドを呼び出すことにより、空の行が追加できます。
dt.Rows.Add();
AddRowメソッドを呼び出すと、DataColumnCollectionに登録されているDataColumnの名前と型でセルと行を作り、DataRowCollectionに登録してくれます。
もう1つの方法として、 NewRow メソッドを使うことも出来ます。
こちらは 空の列を持つDataRowを作るところまではやってくれますが、DataRowCollectionへの登録はしてくれません。
自分で dt.Rows.Add メソッドを使って登録する必要があります。
DataRow dr = dt.NewRow();
dt.Rows.Add(dr);
こちらの方法は2ステップになるので、一見不便そうに見えますが、実はこちらの方法はよく使います。
というのは、NewRowメソッドで取得した空のDataRowに対して、データを入れやすいからです。
参考までに、Rows.ADDを使う例1~3と、NewRowを使う例の4パターンを作ってみました。
最初にRows.ADDを使ってしまうと、わざわざDataRowを取り出す作業が増えてしまいますが、NewRowを使うパターンだと、その作業が不要になるため、全体的にシンプルになります。
//Addメソッドを使う例1
dt.Rows.Add();
dt.Rows[dt.Rows.Count - 1]["カテゴリ"] = "画像";
dt.Rows[dt.Rows.Count - 1]["アプリ"] = "写真AC";
dt.Rows[dt.Rows.Count - 1]["ID"] = "hogehoge";
dt.Rows[dt.Rows.Count - 1]["パスワード"] = "#pass0123!";
//Addメソッドを使う例2
dt.Rows.Add();
int pos = dt.Rows.Count - 1;
dt.Rows[pos]["カテゴリ"] = "画像";
dt.Rows[pos]["アプリ"] = "写真AC";
dt.Rows[pos]["ID"] = "hogehoge";
dt.Rows[pos]["パスワード"] = "#pass0123!";
//Addメソッドを使う例3
dt.Rows.Add();
DataRow dr = dt.Rows[dt.Rows.Count - 1];
dr["カテゴリ"] = "画像";
dr["アプリ"] = "写真AC";
dr["ID"] = "hogehoge";
dr["パスワード"] = "#pass0123!";
//NewRowメソッドを使う例
DataRow dr = dt.NewRow();
dr["カテゴリ"] = "画像";
dr["アプリ"] = "写真AC";
dr["ID"] = "hogehoge";
dr["パスワード"] = "#pass0123!";
dt.Rows.Add(dr);
各セルへのアクセスの方法
DataTableの各セルへは、インデックス又は名前でアクセスが可能です。
どちらが良いという訳ではなく、それぞれメリット、デメリットがあります。
//インデックスを使う方法
DataRow dr = dt.NewRow();
dr[0] = "画像";
dr[1] = "写真AC";
dr[2] = "hogehoge";
dr[3] = "#pass0123!";
dt.Rows.Add(dr);
//名前を使う方法
DataRow dr = dt.NewRow();
dr["カテゴリ"] = "画像";
dr["アプリ"] = "写真AC";
dr["ID"] = "hogehoge";
dr["パスワード"] = "#pass0123!";
dt.Rows.Add(dr);
インデックスを使う方法は、ループ処理の中で値を設定する場合に便利ですが、列の並びが変わると予期せぬ列(セル)に予期せぬ値が格納される心配があります。
逆に、名前をしていする場合は、列の並びが変わっても影響は受けませんが、列名が変わると影響を受けますし、いちいち名前を書くのも面倒です。
従って、ケースバイケースで使い分けて頂く必要があります。
DataGridVIewとの連携
DataGridView に連携する場合、DataGridViewのDataSourceプロパティにDataTableを代入するだけで完了です。
このサンプルでは、uxIdPasswordGrid という名前のDataGridViewコントロールに、DataTableを代入しています。
uxIdPasswordGrid.DataSource = dt;
この操作を行う事で、DataGridViewからデータを変更、追加、削除した内容が、自動的にDataTableにも反映されるようになります。
データのフィルタリングとソート
DataTableの内容を絞り込みしたい場合、DataTableのDefaultView プロパティを使います。
DefaultViewプロパティにはDataViewというクラスが登録されていて、このクラスが持つRowFIlterプロパティに絞り込み条件を設定します。
DataViewクラスには、Sortプロパティがあり、ここにソート項目を設定できます。
下記の例は、”カテゴリ”という名前を持つ列(DataColumn)に対して、”画像” が登録されているDataRowだけ抽出し、カテゴリ、サイト名の順でソートをするサンプルです。
dt.DefaultView.RowFilter = "カテゴリ='画像'";
dt.DefaultView.Sort = "カテゴリ,サイト名";
RowFilterに記述する条件はデータベースからデータを抽出する際に使われるSQLによく似た書き方をします。
値が文字列の場合はシングルクォート で囲みますが、数値の場合はその必要はありません。
like 演算子を使う事で、前方一致、後方一致、曖昧検索を行うことが出来ます。
演算子 | 説明 |
---|---|
= | 指定した値と等しい |
<> | 指定した値と等しくない |
< | 指定した値より小さい |
> | 指定した値より大きい |
<= | 指定した値以上 |
=> | 指定した値以下 |
Is Null | 値がNull |
Like | ド値が指定したパターンと一致する 任意の複数文字はパーセント(%) 任意の一文字はアンダースコア(_) 前方一致の例: Like '画像%' 後方一致の例: Like '%画像' 曖昧検索の例: Like '%画像%' |
NOT | 条件を否定。 NOT Like 、Is NOT Like など |
AND | 指定したすべての条件を満たすレコードを抽出 |
OR | 指定した条件のどれかひとつを満たすレコードを抽出 |
また、組み込み関数として文字列の長さを取得する len(列名) が使えます。
len(商品名) > 5
データの保存と読み込み
DataTableが保持している内容は、WriteXmlメソッドでファイル書き込み、ReadXmlメソッドでファイル読み込みが出来ます。
dt.WriteXml("idpass.xml");
dt.ReadXml("idpass.xml");
ファイルはXML形式で保存されますが、テキスト形式なのでテキストエディタでの編集が可能です。
下記は、保存したファイルのサンプルです。
<?xml version="1.0" standalone="yes"?>
<DocumentElement>
<IdPass>
<カテゴリ>画像サイト</カテゴリ>
<アプリ_x002F_サイト名>写真AC</アプリ_x002F_サイト名>
<ID>hogehoge</ID>
<パスワード>123@5533</パスワード>
</IdPass>
<IdPass>
<カテゴリ>画像サイト</カテゴリ>
<アプリ_x002F_サイト名>パクソタ</アプリ_x002F_サイト名>
<ID>areare</ID>
<パスワード>1335=!aj3Gs</パスワード>
</IdPass>
<IdPass>
<カテゴリ>画像サイト</カテゴリ>
<アプリ_x002F_サイト名>モデルフォト</アプリ_x002F_サイト名>
<ID>modemode</ID>
<パスワード>as11322fasdfs</パスワード>
</IdPass>
<IdPass>
<カテゴリ>通販サイト</カテゴリ>
<アプリ_x002F_サイト名>楽天</アプリ_x002F_サイト名>
<ID>rakuraku</ID>
<パスワード>1#%#9s125taj-^#</パスワード>
</IdPass>
<IdPass>
<カテゴリ>通販サイト</カテゴリ>
<アプリ_x002F_サイト名>アマゾン</アプリ_x002F_サイト名>
<ID>amaama</ID>
<パスワード>2234#%%12323#</パスワード>
</IdPass>
</DocumentElement>
まとめ
今回は、表形式のデータを扱う際によく使われるDataTableの基本的な構造と、その使い方について解説しました。
DataTableは、行をつかさどるDataRowクラスと、列をつかさどるDataColumnクラスで構成されており、指定した条件でフィルタリングしたり、XML形式でのファイル保存や読み込み機能が搭載されています。
特にCSVファイルやリレーショナルデータベースとの相性が良いので、本格的にC#を学習される方は、是非この機会にDataTableの扱い方をマスターしてください。