今回はデータセットに読み込んだレコードを編集し、それをデータベースに反映する。複数ユーザーからの同時アクセスについても考えてみる。
前回では、データセットとデータアダプタを利用した非接続型のデータベース・アクセスにおけるレコードの追加について解説した。続いて今回はレコードの更新について解説していく。
念のため書いておくと、レコードの更新とは、すでにテーブルに存在するレコードに含まれているカラムのデータを新しい値で書き換えることである。通常、テーブルにはレコードを一意に識別できる主キーとなるカラム(あるいは複数のカラムの組み合わせ)が設定されている。従って、更新対象のレコードを主キーで指定し、そのカラムのデータを書き換えることになる。
まずは、データセットにテーブルの内容を読み込み、その内容を書き換えるところから始める。
データセットにテーブルを読み込むまでは、すでに前回および前々回でも解説している。ここでもこれまでどおり、MSDEのサンプル・データベースであるpubsデータベースのpublishersテーブルからpub_idカラムとpub_nameカラムについて、すでに全レコードを取得しているとしよう。
データテーブルのオブジェクトを変数dtで参照しているとすると、サンプル・データベースをインストールした直後では、dtから参照できる各レコードであるDataRowオブジェクトのデータは次の表のようになっているはずだ。
参照方法 | 値 |
---|---|
dt.Rows[0]["pub_id"] | 0736 |
dt.Rows[0]["pub_name"] | New Moon Books |
dt.Rows[1]["pub_id"] | 0877 |
dt.Rows[1]["pub_name"] | Binnet & Hardley |
dt.Rows[2]["pub_id"] | 1389 |
dt.Rows[2]["pub_name"] | Algodata Infosystems |
dt.Rows[3]["pub_id"] | 1622 |
dt.Rows[3]["pub_name"] | Five Lakes Publishing |
dt.Rows[4]["pub_id"] | 1756 |
dt.Rows[4]["pub_name"] | Ramona Publishers |
dt.Rows[5]["pub_id"] | 9901 |
dt.Rows[5]["pub_name"] | GGG&G |
dt.Rows[6]["pub_id"] | 9952 |
dt.Rows[6]["pub_name"] | Scootney Books |
dt.Rows[7]["pub_id"] | 9999 |
dt.Rows[7]["pub_name"] | Lucerne Publishing |
データテーブルに読み込んだpublishersテーブルの初期値 |
いま、データテーブル内にあるpub_idカラムの値が「1756」のレコードの、pub_nameカラムにある「Ramona Publishers」という値を「ラモーナ出版」と書き換えてみよう。これは単純に次のようなコードで記述できる。
dt.Rows[4]["pub_name"] = "ラモーナ出版";
もちろんこの記述は、DataTalbeオブジェクトのDataRowオブジェクトのコレクションであるRowsプロパティの4番目のDataRowオブジェクトで、そのpub_idカラムの値が「1756」とすでに分かっている場合である。実際には、更新対象となるDataRowオブジェクトを見つけ出すことから始めなければならない。
データセット内から更新対象となるレコードを取り出す方法はいくつか用意されているが、主キーとなるカラムの値からレコードを取得するには、DataRowCollectionクラスのFindメソッドが利用できる。これは次のようにしてパラメータとして主キー・カラムの値を指定する。
DataRow targetRow = dt.Rows.Find("1756");
今回対象としているpublishersテーブルには、主キーとして「pub_id」カラムが設定されており、そのカラムの型は文字列型である。
ただし、このFindメソッドを利用する場合には、DataTableオブジェクト(ここでは変数dt)において、あらかじめ主キーを設定しておく必要がある。主キーの指定は、DataTableオブジェクトのPrimaryKeyプロパティに、主キーとなるカラムを表すDataColumnオブジェクトの配列をセットする。
dt.PrimaryKey = new DataColumn[] { dt.Columns["pub_id"] };
カラムの配列を指定するのは、主キーが複数のカラムからなる場合があるためである。この例では主キーとなるカラムはpub_idカラムだけなので、配列の要素は1つだけとなる。
さて、ここまでの手順を実行可能なプログラムとしてまとめておこう。次のサンプル・プログラムはpublishersテーブルからデータセットにレコードを読み込み、そのうちの「pub_id = "1756"」のレコードのpub_nameカラムを書き換える。まだ書き換えた内容をデーベースへは反映しない。
// updaterow.cs
using System;
using System.Data;
using System.Data.SqlClient;
public class UpdateDataRow {
public static void Main() {
string connStr = "Server=(local)\\NetSDK;"
+ "Trusted_Connection=yes;"
+ "database=pubs";
string selectStr
= "SELECT pub_id, pub_name FROM publishers";
// 接続用オブジェクトの作成
SqlConnection conn = new SqlConnection();
conn.ConnectionString = connStr;
// select用コマンド・オブジェクトの作成
SqlCommand selectCmd = new SqlCommand();
selectCmd.Connection = conn;
selectCmd.CommandText = selectStr;
// データアダプタの作成
SqlDataAdapter da = new SqlDataAdapter();
da.SelectCommand = selectCmd;
// データセットへの読み込み
DataSet ds = new DataSet();
da.Fill(ds, "publishers");
DataTable dt = ds.Tables["publishers"];
// 主キーの設定
dt.PrimaryKey = new DataColumn[] { dt.Columns["pub_id"] };
// データの更新
DataRow targetRow;
targetRow = dt.Rows.Find("1756");
targetRow["pub_name"] = "ラモーナ出版";
}
}
// コンパイル方法:csc updaterow.cs
■Selectメソッドによるレコードの検索
なお、データテーブルからレコードを主キーに関係なく検索するためのメソッドも用意されている。DataTableクラスのSelectメソッドである。このメソッドでは、パラメータに検索条件を文字列で指定できる。この検索条件はSQLのselect文のwhere句に指定する条件と似ている。
Selectメソッドの利用例は次のようになる。
DataRow[] targetRows;
targetRows = dt.Select("pub_id = '1756'");
また、例えばpub_nameカラムの値で検索する場合は次のようになる。
targetRows = dt.Select("pub_name = 'Ramona Publishers'");
Selectメソッドでは、select文と同様にかなり多様な条件を指定することができ、レコードの並び替えなどの機能も用意されている。詳しくはリファレンス・マニュアルのSelectメソッドの項目を参照していただきたい。
ただし主キーで検索する場合と異なり、Selectメソッドでは複数のDataRowオブジェクトが見つかる場合がある点には注意が必要だ。
■主キーを設定するための別の方法
ところで、Findメソッドを使用する前に、なぜわざわざ主キーとなるカラムを自分で設定する必要があるのだろうか?
第4回でも述べているように、データアダプタのFillメソッドは、レコードを読み込むのと同時にテーブルのカラム情報も取得しており、それらはDataColumnオブジェクトとしてデータテーブルのColumnsプロパティにセットされている。上記のサンプル・プログラムで、dt.Columns["pub_id"]としてpub_idカラムのDataColumnオブジェクトを指定できるのはこのためだ。
しかし、デフォルトではテーブルに設定されている主キーについてのスキーマ情報はデータテーブルにはセットされない。これがデフォルトでないのは、主キーを含めたカラム情報の取得は処理に少し時間がかかるためだ。Fillメソッドの呼び出し時に主キー情報も取得するには、次のようにデータアダプタのMissingSchemaActionプロパティにMissingSchemaAction.AddWithKeyを設定すればよい(デフォルトの値はMissingSchemaAction.Add)。
// データアダプタの作成
SqlDataAdapter da = new SqlDataAdapter();
da.MissingSchemaAction = MissingSchemaAction.AddWithKey;
da.SelectCommand = selectCmd;
もちろんこの場合には、データテーブルのPrimaryKeyプロパティの設定は不要である。この場合には、逆に次のようなコードにより主キーの情報にアクセスできる。このコードは主キーとなっているカラムのカラム名を表示する。
foreach (DataColumn dc in dt.PrimaryKey) {
Console.WriteLine(dc.ColumnName);
}
さらに別の方法としては、データアダプタのFillSchemaメソッドを使用してデータテーブルに主キー情報を設定することもできるが、これについてはここでは割愛させていただく。リファレンス・マニュアルの「DataSet への既存の制約の追加」にもあるように、主キーの設定は最適なパフォーマンスを得るためにPrimaryKeyプロパティを使用すべきである。プログラムで扱うテーブルの主キーが不明、ということはないはずだ。
Copyright© Digital Advantage Corp. All Rights Reserved.