非接続型であるデータセットを使った場合のレコード追加について解説。ADO.NETには必要なSQL文を自動作成する機能も用意されている。
ADO.NETによるデータベースのアクセスには大きく分けて2つの方法がある。1つは第2回および第3回で解説した.NETデータ・プロバイダによる「接続型」のアクセスである。そしてもう1つがデータセットとデータアダプタによる「非接続型」のアクセスである。前回の第4回では、非接続型のアクセスによりデータベースからレコードを取得した。今回および次回では、非接続型でのデータベース更新について解説する。
データベースの更新を行う前に、前回で解説したデータセットとデータアダプタによるレコードの取得について、次に示すサンプル・プログラムで簡単に復習しておこう。このプログラムでは、MSDEのサンプル・データベースであるpubsデータベースに接続してpublishersテーブルからpub_idカラムとpub_nameカラムについて全レコードを取得し、「publishers」という名前を付けたデータセット内のデータテーブルに読み込んでいる。
// dsfill.cs
using System;
using System.Data;
using System.Data.SqlClient;
public class DataSetFill {
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");
}
}
// コンパイル方法:csc dsfill.cs
前回では、よりコード量が少ない記述例も示したが、ここでは次の図に示しているようなオブジェクトの構成が見えやすい形でコーディングを行っている。
プログラムでは、一番最後にあるFillメソッドの呼び出しによりデータベースとの接続が行われ、SqlCommandオブジェクトにセットしておいたselect文が実行される。その結果取得されたレコードは、DataSetオブジェクト内に生成されたDataTableオブジェクト中にDataRowオブジェクトとして格納される。
今回から行おうとしているデータセットによるデータベースの更新とは、このようにして作成したDataTableオブジェクトのレコードを編集し、その変更内容を、データアダプタを利用してデータベースに反映するというものだ。まず今回では、データベースへのレコードの追加について解説する。これは、DataTableオブジェクトに新しいレコードを追加し、そしてそれをSqlDataAdapterオブジェクトによりデータベースに反映させるという処理である。
DataTableオブジェクトへレコードを追加するには、レコードであるDataRowオブジェクトを新しく1つ作成し、各カラムに値を設定してから、それをDataTableオブジェクトのRowsコレクションに追加する。DataRowオブジェクトとDataTaleオブジェクトの関連については、前回の「データセット内の項目へのアクセス」を参照していただきたい。
新しいDataRowオブジェクトは、DataRowクラスのコンストラクタを呼び出して作るのではなく、DataTableクラスのNewRowメソッドにより作成する。そもそもpublicなDataRowクラスのコンストラクタは用意されていないので、newによりそのインスタンスを作成することはできない。これは、DataRowオブジェクトが常に列についての情報が必要であるということを意味している。列についての情報は、DataTableオブジェクトのみがDataColumnオブジェクトとして保持しているためだ。
データセット内にpublishersという名前のDataTableオブジェクトが存在する場合、次のようにして新しいDataRowオブジェクトを作成することができる。
DataTable dt = ds.Tables["publishers"];
DataRow newRow = dt.NewRow();
こうして作成したDataRowオブジェクトは、DataTableオブジェクト内の既存のレコードと同様に、すでにpub_idとpub_nameの2つのカラムを持っている。それぞれに新しいデータをセットし、DataTableオブジェクトのDataRowオブジェクトのコレクションであるRowsプロパティに、Addメソッドを使用してレコードを追加すればよい。
newRow["pub_id"] = "9990";
newRow["pub_name"] = "@IT Insider.NET";
dt.Rows.Add(newRow);
ここまでの処理を図にすると次のようになる。
次に、データセットの内容をデータアダプタを経由してデータベースに反映する。レコードの取得処理がFillメソッド呼び出し一発でできたように、反映処理も1つのメソッドで可能だ。Fillメソッドと逆の働きをするこのメソッドは「Updateメソッド」である。必要なパラメータもFillメソッドと同じだ。
da.Update(ds, "publishers");
とりあえずこのコードを追加してプログラムを実行してみよう。だがこれを実行すると、残念ながら次のようなメッセージの例外が発生するはずだ。
更新には、新しい行を含む DataRow コレクションが渡されたとき、有効な InsertCommand が必要です。
メッセージ中の「InsertCommand」とは、SqlDataAdapterオブジェクトのInsertCommandプロパティのことである。つまりこのメッセージはInsertCommandプロパティに何かをセットする必要があるということを意味している。
データの取得時には、Fillメソッドを実行するのにselect文をセットしたSqlCommandオブジェクトが必要で、これはSelectCommandプロパティにセットされるものであるということはこれまでに何度か説明してきたとおりである。
同様に、データセットに新しく追加されたレコードが含まれている場合、そのレコードを処理するためにUpdateメソッドはInsertCommandプロパティにセットされたSqlCommandオブジェクトを使用するのである。このSqlCommandオブジェクトに必要なSQL文はもちろん、データベースにレコードを追加するためのinsert文である。
もしデータセットに複数の新しいレコードが追加されている場合には、それぞれの新しいレコードについてinsert用のSqlCommandオブジェクトが繰り返し使用されることになる。
Copyright© Digital Advantage Corp. All Rights Reserved.