C# ADO.NET SqlDataAdapter によるストアドプロシージャ呼び出しで DataSet にデータを読み込む
前回は SqlDataReader を使って順方向専用のストリーム読み取りを行いました。今回は SqlDataAdapter を使用し、ストアドプロシージャの実行結果をまとめてDataSet(メモリ上のオフラインテーブル)へ格納します。DataGridView などのコントロールへデータバインドする場面でよく使われます。SqlCommand(ストアドプロシージャ定義) → SqlDataAdapter.SelectCommand → adapter.Fill(DataSet) でデータを自動取得
サンプルコード
string connectionString = "Data Source=.;Initial Catalog=db;Integrated Security=SSPI;";
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
SqlCommand sqlCom = new SqlCommand();
sqlCom.Connection = conn;
sqlCom.CommandText = "myProc";
// 実行種別をストアドプロシージャに指定
sqlCom.CommandType = CommandType.StoredProcedure;
// ストアドプロシージャへ入力パラメータを渡す
SqlParameter param = new SqlParameter("@id", SqlDbType.Int, 8);
param.Value = 4;
param.Direction = ParameterDirection.Input;
sqlCom.Parameters.Add(param);
// データアダプター
SqlDataAdapter sqlDA = new SqlDataAdapter();
sqlDA.SelectCommand = sqlCom;
DataSet ds = new DataSet();
// データを読み込み、第2引数はDataSet内のテーブル名
sqlDA.Fill(ds, "sdfdsf");
// WinFormsグリッドコントロールへバインド
this.dataGridView1.DataSource = ds.Tables[0];
}Code language: C# (cs)
より良い記述例
string connectionString = "Data Source=.;Initial Catalog=db;Integrated Security=SSPI;";
using (SqlConnection conn = new SqlConnection(connectionString))
{
string procName = "myProc";
using (SqlCommand sqlCom = new SqlCommand(procName, conn))
{
sqlCom.CommandType = CommandType.StoredProcedure;
// パラメータを簡潔に設定
sqlCom.Parameters.Add("@id", SqlDbType.Int).Value = 4;
SqlDataAdapter sqlDA = new SqlDataAdapter(sqlCom);
DataSet ds = new DataSet();
// 結果セットを読み込み、テーブルに別名 ArticleResult を付ける
sqlDA.Fill(ds, "ArticleResult");
// コントロールへバインド
dataGridView1.DataSource = ds.Tables["ArticleResult"];
// インデックスによるアクセスも可:ds.Tables[0]
}
}Code language: JavaScript (javascript)
解説
SqlDataAdapter.Fill() の仕様
- 接続の自動制御:
Fill実行時に接続がOpen()されていない場合、アダプターが内部で接続を開き、処理終了後自動で閉じます。
サンプルコードでは明示的に
conn.Open()を呼んでいますが、必須ではありません。動作はします。
Fill(ds, "テーブル名"):メモリ上に作成されるDataTableに名前を設定し、名前指定で参照できるようにします。省略すると既定でTableという名前になります。- ストアドプロシージャが複数の結果セットを返す場合、
Fillは複数のDataTableを自動生成します:ds.Tables[0]、ds.Tables[1]...
DataSet と SqlDataReader の主な違い
| オブジェクト | 動作モード | 接続占有 | 利用シーン |
|---|---|---|---|
| SqlDataReader | 接続保持型ストリーム読取 | DB接続を開いたまま維持 | 大量データ、全キャッシュ不要、1行ごと処理 |
| DataSet(DataAdapter) | オフラインメモリキャッシュ | Fill完了後接続を解放 | UIコントロールバインド、小規模データ、繰り返し参照 |
ストアドプロシージャ実行に必須の設定
sqlCom.CommandType = CommandType.StoredProcedure;
この1行が無いと、ADO.NETは myProc を普通のSQL文として解釈し実行し、エラーが発生します。
コントロールへのバインド
dataGridView1.DataSource = ds.Tables[0];
WinForms の DataGridView は DataTable を直接バインド可能で、カラムが自動生成されます。
データ変更後にデータベースへ反映したい場合は SqlDataAdapter.Update() を使って一括更新が行えます。
明示的に接続を Open しない書き方
using(SqlConnection conn=new SqlConnection(connectionString))
using(SqlCommand cmd=new SqlCommand("myProc",conn))
{
cmd.CommandType=CommandType.StoredProcedure;
cmd.Parameters.Add("@id",SqlDbType.Int).Value=4;
SqlDataAdapter da=new SqlDataAdapter(cmd);
DataSet ds=new DataSet();
da.Fill(ds,"Article"); // 接続の開閉を自動処理
}Code language: JavaScript (javascript)
上記コードでは using 文で接続リソースを管理しています
SqlDataAdapter
Previous: SqlDataReader
Next: ストアドプロシージャ Return