第5回 データセットを使ったレコードの追加:基礎解説 ADO.NET基礎講座 ―初めての.NETデータベース・プログラミング―(2/3 ページ)
非接続型であるデータセットを使った場合のレコード追加について解説。ADO.NETには必要なSQL文を自動作成する機能も用意されている。
insert用SqlCommandオブジェクトの作成
それでは、insert文をセットしたSqlCommandオブジェクトを作成してみよう。このときinsert文はどのようなものになるだろうか。いま述べたように、データセット内の新しいレコードは複数あるかもしれないので、次のようなデータを直接埋め込んだinsert文はここでは役に立たない。
insert into publishers (pub_id, pub_name)
values ("9990", "@IT Insider.NET")
汎用的に利用できるinsert文は、「名前付きパラメータ」を利用して次のように記述できる。
insert into publishers(pub_id, pub_name) values (@PubId, @PubName)
名前付きパラメータ(@PubIdや@PubName)を利用したinsert文の記述については「連載第3回のパラメータを利用したSQL文」ですでに解説している。パラメータ部分に置き換える実際の値の指定は、SqlParameterオブジェクトを使用して行う。
ここで問題となるのは、どうやって名前付きパラメータとデータテーブル内のカラムを結び付けるかということだが、結論からいうとSqlParameterオブジェクトには、そのソースとなるデータセット内のカラム名を指定するためのSourceColumnプロパティが用意されている。このプロパティを利用したinsert用のSqlCommandオブジェクト作成のためのコードは次のようになる。
string insertStr = "INSERT INTO publishers(pub_id, pub_name) VALUES (@PubId, @PubName)";
SqlCommand insertCmd = new SqlCommand();
insertCmd.Connection = conn;
insertCmd.CommandText = insertStr;
SqlParameter p1 = new SqlParameter();
p1.ParameterName = "@PubId";
p1.SourceColumn = "pub_id";
insertCmd.Parameters.Add(p1);
SqlParameter p2 = new SqlParameter();
p2.ParameterName = "@PubName";
p2.SourceColumn = "pub_name";
insertCmd.Parameters.Add(p2);
カラムの型が基本的な型であれば、最低限ParameterNameプロパティとSourceColumnプロパティをセットしておけばよい。
レコードを追加するサンプル・プログラム
ここまでに示したレコード追加のためのコードを、ひとまず実行可能なサンプル・プログラムとしてまとめておこう。このサンプル・プログラムは実行しても何も出力しないので、実際にレコードが正しく追加されているかどうかは、前回で示したデータセット表示のためのプログラムなどを使って確認していただきたい。
// insertds.cs
using System;
using System.Data;
using System.Data.SqlClient;
public class InsertFromDataSet {
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"];
// 行の追加
DataRow newRow = dt.NewRow();
newRow["pub_id"] = "9990";
newRow["pub_name"] = "@IT Insider.NET";
dt.Rows.Add(newRow);
// insert用コマンド・オブジェクトの作成
string insertStr
= "INSERT INTO publishers(pub_id, pub_name)"
+ " VALUES (@PubId, @PubName)";
SqlCommand insertCmd = new SqlCommand();
insertCmd.Connection = conn;
insertCmd.CommandText = insertStr;
SqlParameter p1 = new SqlParameter();
p1.ParameterName = "@PubId";
p1.SourceColumn = "pub_id";
insertCmd.Parameters.Add(p1);
SqlParameter p2 = new SqlParameter();
p2.ParameterName = "@PubName";
p2.SourceColumn = "pub_name";
insertCmd.Parameters.Add(p2);
da.InsertCommand = insertCmd;
// データベースの更新
da.Update(ds, "publishers");
}
}
// コンパイル方法:csc insertds.cs
insertds.csのダウンロード
ちなみに、publishersテーブルではpub_idカラムのデータはテーブル内でユニークでなければならないので、このプログラムを2度続けて実行すると、2回目の実行はエラーになる。
insert文の自動生成
いま示したサンプル・プログラムでは、SqlCommandオブジェクトにinsert文を設定し、SqlParameterオブジェクトによりパラメータの設定を行うという記述をしたが、ADO.NETにはこれらの作業を自動で行ってくれる便利なクラスが用意されている。SqlCommandBuilderクラスがそれである。
SqlCommandBuilderクラスを利用して、上記のサンプル・プログラム(insertds.cs)を書き換えると次のようになる。
// cbinsertds.cs
using System;
using System.Data;
using System.Data.SqlClient;
public class BuilderInsertFromDataSet {
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"];
// 行の追加
DataRow newRow = dt.NewRow();
newRow["pub_id"] = "9990";
newRow["pub_name"] = "@IT Insider.NET";
dt.Rows.Add(newRow);
// コマンド自動作成
SqlCommandBuilder cb = new SqlCommandBuilder(da);
// データベースの更新
da.Update(ds, "publishers");
}
}
// コンパイル方法:csc cbinsertds.cs
cbinsertds.csのダウンロード
リストを見れば分かるように、単にSqlDataAdapterオブジェクトをパラメータにしてSqlCommandBuilderクラスのインスタンスを作成するだけだ。これだけでデータアダプタのInsertCommandプロパティには、insert文とそれに必要なSqlParameterオブジェクトを含んだSqlCommandオブジェクトが自動的に設定される。
先に述べておくと、SqlCommandBuilderクラスによる自動生成は、insert文だけでなく、update文とdelete文も自動的に作成してくれる。このためデータベース更新のためのコードを非常にすっきりと記述することができる。また、select文さえしっかりと記述できれば、そのほかのSQL文についてあまり詳しくなくても取りあえずデータベースの更新ができるという利点もある。
ところで、上記のコードでは作成したSqlCommandBuilderオブジェクトを変数cbに代入しているが、それを一度も利用していない(実際、このプログラムでは代入処理は必要ない)。コンストラクタのパラメータにデータアダプタを渡すだけで、なぜInsertCommandプロパティにSqlCommandオブジェクトが設定されるのだろうか。
実はこの時点では、InsertCommandプロパティは設定されず、SqlCommandBuilderオブジェクトは自分のメソッドをデータアダプタのRowUpdatingイベントに登録するだけだ。RowUpdatingイベントは、データアダプタのUpdateメソッドが実行されたときに発生するイベントで、insert文がセットされたSqlCommandBuilderオブジェクトが実際に作成されるのはこのイベントが発生したタイミングである。ただし、このようにして一度オブジェクトが作成されると(すでにInsertCommandプロパティが設定されていると)、以降は同じものがUpdateメソッドで使用される。また、データセットにレコードの追加だけしか行っていない場合には、update文やdelete文用のSqlCommandオブジェクトは作成されない。
Copyright© Digital Advantage Corp. All Rights Reserved.