はじめに
.NET アプリでデータベースに接続できました。
.NET アプリでデータベースに接続する #MySQL - Qiita
接続したデータベースを操作してみます。
以下の環境で開発および動作を確認します。
- Windows 11
- Visual Studio 2022
- .NET Framework 4.5.2 または .NET 8.0
.NET アプリでデータベースを操作する
Microsoft SQL Server を用意する
まず、Microsoft SQL Server を用意します。
SQL Server Express(無料版)を導入する #SQLServer - Qiita
さらに、サンプルデータを導入しておきましょう。
SQL Server:サンプルデータベース「Northwind」を作成する方法 | SE Life Log
データベース「pub」に接続して操作するので導入しておきます。↑
Microsoft SQL Server に接続する .NET アプリを作成する
Visual Studio で「新しいプロジェクトの作成」して Windows フォームアプリ
または Windows フォームアプリ (.NET Framework)
を選択します。
フレームワークは .NET Framework 4.5.2
または .NET 8.0
を選択します。
ボタン(Button)とテキストボックス(TextBox)とデータグリッド(DataGridView)をフォームに配置します。
Visual Studio の「Nuget パッケージの管理」を開いて Microsoft.Data.SqlClient
をインストールします。
データベースに接続する・・①
SqlConnection
を使ってデータベースに接続します。
参考:C#でDBに接続する方法(SQL Server) #SQLServer - Qiita
using Microsoft.Data.SqlClient;
string conStr = "Server=127.0.0.1; User ID=sa; Password=......; Encrypt=false; Database=pubs;";
private void button1_Click(object sender, EventArgs e)
{
textBox0.Clear();
textBox1.Clear();
try
{
SqlConnection cn = new SqlConnection();
cn.ConnectionString = conStr;
cn.Open();
textBox0.Text = "Connected.";
cn.Close();
}
catch (Exception ex)
{
textBox0.Text = "Error:" + ex.Message;
}
}
DataReader で読込する・・②
SqlCommand
でクエリを実行して、その結果を SqlDataReader
で一行ずつ読込します。
参考:SELECT文でデータを取得する(DataReader)。猫の気ままなC#日記
前略
SqlConnection cn = new SqlConnection();
cn.ConnectionString = conStr;
cn.Open();
textBox0.Text = "Connected."; // ↑ここまで同じ
SqlCommand cmd = new SqlCommand();
cmd.Connection = cn;
cmd.CommandText = "SELECT TOP 5 * FROM titles;";
SqlDataReader dr = cmd.ExecuteReader(); // クエリを実行
while (dr.Read()) // 一行ずつ読込
{
textBox1.AppendText($"{dr[0]} {dr[1]} {dr[4]} {dr[9]}\r\n");
}
dr.Close();
cn.Close(); // ↓ここから同じ
後略
省略しないコード
private void button2_Click(object sender, EventArgs e)
{
textBox0.Clear();
textBox1.Clear();
try
{
SqlConnection cn = new SqlConnection();
cn.ConnectionString = conStr;
cn.Open();
textBox0.Text = "Connected.";
SqlCommand cmd = new SqlCommand();
cmd.Connection = cn;
cmd.CommandText = "SELECT TOP 5 * FROM titles;";
SqlDataReader dr = cmd.ExecuteReader(); // クエリを実行
while (dr.Read()) // 一行ずつ読込
{
textBox1.AppendText($"{dr[0]} {dr[1]} {dr[4]} {dr[9]}\r\n");
}
dr.Close();
cn.Close();
}
catch (Exception ex)
{
textBox0.Text = "Error:" + ex.Message;
}
}
DataReader で読込する・・③
エラー発生したとき Close()
できないといけないので、try ~ finally
を使います。
前略
try
{
SqlCommand cmd = new SqlCommand();
cmd.Connection = cn;
cmd.CommandText = "SELECT TOP 5 * FROM titles;";
SqlDataReader dr = cmd.ExecuteReader(); // クエリを実行
try
{
while (dr.Read()) // 一行ずつ読込
{
textBox1.AppendText($"{dr[0]} {dr[1]} {dr[4]} {dr[9]}\r\n");
}
}
finally
{
dr.Close();
}
}
finally
{
cn.Close();
}
後略
省略しないコード
private void button3_Click(object sender, EventArgs e)
{
textBox0.Clear();
textBox1.Clear();
try
{
SqlConnection cn = new SqlConnection();
cn.ConnectionString = conStr;
cn.Open();
textBox0.Text = "Connected.";
try
{
SqlCommand cmd = new SqlCommand();
cmd.Connection = cn;
cmd.CommandText = "SELECT TOP 5 * FROM titles;";
SqlDataReader dr = cmd.ExecuteReader(); // クエリを実行
try
{
while (dr.Read()) // 一行ずつ読込
{
textBox1.AppendText($"{dr[0]} {dr[1]} {dr[4]} {dr[9]}\r\n");
}
}
finally
{
dr.Close();
}
}
finally
{
cn.Close();
}
}
catch (Exception ex)
{
textBox0.Text = "Error:" + ex.Message;
}
}
DataReader で読込して DataTable にセットする・・④
DataTable
オブジェクトを用意して、DataReader
で読込した内容をセットします。
前略
SqlDataReader dr = cmd.ExecuteReader(); // ↑ここまで同じ
DataTable dt = new DataTable(); // DataTable を用意
dt.Columns.Add("title_id"); // 列を追加
dt.Columns.Add("title");
dt.Columns.Add("price");
dt.Columns.Add("pubdate");
try
{
while (dr.Read()) // 一行ずつ読込
{
DataRow row = dt.Rows.Add(); // 行を追加
row["title_id"] = dr["title_id"];
row["title"] = dr["title"];
row["price"] = dr["price"];
row["pubdate"] = dr["pubdate"];
}
}
後略
省略しないコード
private void button4_Click(object sender, EventArgs e)
{
textBox0.Clear();
textBox1.Clear();
try
{
SqlConnection cn = new SqlConnection();
cn.ConnectionString = conStr;
cn.Open();
textBox0.Text = "Connected.";
try
{
SqlCommand cmd = new SqlCommand();
cmd.Connection = cn;
cmd.CommandText = "SELECT TOP 5 * FROM titles;";
SqlDataReader dr = cmd.ExecuteReader(); // クエリを実行
DataTable dt = new DataTable(); // DataTable を用意
dt.Columns.Add("title_id"); // 列を追加
dt.Columns.Add("title");
dt.Columns.Add("price");
dt.Columns.Add("pubdate");
try
{
while (dr.Read()) // 一行ずつ読込
{
DataRow row = dt.Rows.Add(); // 行を追加
row["title_id"] = dr["title_id"];
row["title"] = dr["title"];
row["price"] = dr["price"];
row["pubdate"] = dr["pubdate"];
}
}
finally
{
dr.Close();
}
foreach (DataRow row in dt.Rows) // 一行ずつ処理
{
textBox1.AppendText($"{row[0]} {row[1]} {row[2]} {row[3]}\r\n");
}
}
finally
{
cn.Close();
}
}
catch (Exception ex)
{
textBox0.Text = "Error:" + ex.Message;
}
}
データベースのテーブルは、列ごとにデータ型が指定されています。DataTable
の列も同様に、データ型
属性を持っています。列を追加するときデータ型を指定するのが望ましい。
今回は名前だけ指定しています。デフォルトで String
型になるようです。
参考:列に指定した型をつけてDataTableを作成する | 猫の気ままなC#日記
DataTable に DataReader から Load する・・⑤
DataTable
オブジェクトにデータをセットするのに Load()
を使ってみます。
上記④は DataTable
に列を事前に定義していますが、Load()
はデータをセットするとき列もセットしてくれます。
参考:DataReaderで取得したデータからDataTableを作成する - チャトラのプログラミング学習帳
前略
SqlDataReader dr = cmd.ExecuteReader(); // ↑ここまで同じ
DataTable dt = new DataTable(); // DataTable を用意
try
{
dt.Load(dr); // ループで処理する代わり
}
後略
省略しないコード
private void button5_Click(object sender, EventArgs e)
{
textBox0.Clear();
textBox1.Clear();
try
{
SqlConnection cn = new SqlConnection();
cn.ConnectionString = conStr;
cn.Open();
textBox0.Text = "Connected.";
try
{
SqlCommand cmd = new SqlCommand();
cmd.Connection = cn;
cmd.CommandText = "SELECT TOP 5 * FROM titles;";
SqlDataReader dr = cmd.ExecuteReader(); // クエリを実行
DataTable dt = new DataTable(); // DataTable を用意
try
{
dt.Load(dr); // ループで処理する代わり
}
finally
{
dr.Close();
}
}
finally
{
cn.Close();
}
foreach (DataRow row in dt.Rows) // 一行ずつ処理
{
textBox1.AppendText($"{row[0]} {row[1]} {row[4]} {row[9]}\r\n");
}
}
catch (Exception ex)
{
textBox0.Text = "Error:" + ex.Message;
}
}
Load()
は DataTable
に列をセットするとき、列ごとに データ型
もセットしてくれます。DataReader
がデータベースからデータを読取するときテーブルの列のデータ型も取得していて、これを参照しているのでしょう。
上記のコードで「price」列は Decimal
、「pubdate」列は DateTime
になっていました。
DbCommand でデータベースを更新する・・⑥
DbCommand
の派生クラス SqlCommand
を使って、データベースを更新するクエリを実行します。
参考:テーブルを書き換えるSQLの実行 | データベース千夜一夜 - PowerNews連載コラム
前略
try
{
SqlCommand cmd = new SqlCommand();
cmd.Connection = cn;
cmd.CommandText = "INSERT INTO sales (stor_id, ord_num, ord_date, qty, payterms, title_id) " +
$" VALUES ('8042', '99999999', CAST(CURRENT_TIMESTAMP AS DATE), 9, 'on invoice', 'TC7777');";
cmd.ExecuteNonQuery(); // クエリを実行
textBox0.Text = "Executed.";
}
後略
省略しないコード
private void button6_Click(object sender, EventArgs e)
{
textBox0.Clear();
textBox1.Clear();
try
{
SqlConnection cn = new SqlConnection();
cn.ConnectionString = conStr;
cn.Open();
textBox0.Text = "Connected.";
try
{
SqlCommand cmd = new SqlCommand();
cmd.Connection = cn;
cmd.CommandText = "INSERT INTO sales (stor_id, ord_num, ord_date, qty, payterms, title_id) " +
$" VALUES ('8042', '99999999', CAST(CURRENT_TIMESTAMP AS DATE), 9, 'on invoice', 'TC7777');";
cmd.ExecuteNonQuery(); // クエリを実行
textBox0.Text = "Executed.";
}
finally
{
cn.Close();
}
}
catch (Exception ex)
{
textBox0.Text = "Error:" + ex.Message;
}
}
データベース「pub」のテーブル「sales」は、フィールド「stor_id」「ord_num」「title_id」が主キーに設定されています。このフィールドが同じ値のデータは複数追加できません。したがって、上記のコードを複数実行すると、キー違反のエラーになります。また、フィールド「stor_id」と「title_id」は、それぞれテーブル「stores」「titles」に参照設定されています。したがって、「stores」「titles」に登録されていない値を「stor_id」「title_id」にセットすると、不整合のエラーになります。下記の⑬や⑰の処理したときも同様です。
Transaction を使う・・⑦
SqlTransaction
オブジェクトを用意して、実行時にエラー発生したとき Rollback()
できるようにしましょう。
参考:[ADO.NETの基本的なコード:トランザクション処理]@[VB.NETde業務アプリ]
前略
SqlCommand cmd = new SqlCommand();
cmd.Connection = cn;
cmd.CommandText = "INSERT INTO sales (stor_id, ord_num, ord_date, qty, payterms, title_id) " +
$" VALUES ('8042', '{GetRandomString(8)}', CAST(CURRENT_TIMESTAMP AS DATE), 9, 'on invoice', 'TC7777');";
SqlTransaction tx = cn.BeginTransaction(); // トランザクションを開始
try
{
cmd.Transaction = tx;
cmd.ExecuteNonQuery(); // クエリを実行
tx.Commit(); // 確定する
textBox0.Text = "Executed.";
}
catch
{
tx.Rollback(); // 取消する
throw;
}
後略
省略しないコード
private void button7_Click(object sender, EventArgs e)
{
textBox0.Clear();
textBox1.Clear();
try
{
SqlConnection cn = new SqlConnection();
cn.ConnectionString = conStr;
cn.Open();
textBox0.Text = "Connected.";
try
{
SqlCommand cmd = new SqlCommand();
cmd.Connection = cn;
cmd.CommandText = "INSERT INTO sales (stor_id, ord_num, ord_date, qty, payterms, title_id) " +
$" VALUES ('8042', '{GetRandomString(8)}', CAST(CURRENT_TIMESTAMP AS DATE), 9, 'on invoice', 'TC7777');";
SqlTransaction tx = cn.BeginTransaction(); // トランザクションを開始
try
{
cmd.Transaction = tx;
cmd.ExecuteNonQuery(); // クエリを実行
tx.Commit(); // 確定する
textBox0.Text = "Executed.";
}
catch
{
tx.Rollback(); // 取消する
throw;
}
}
finally
{
cn.Close();
}
}
catch (Exception ex)
{
textBox0.Text = "Error:" + ex.Message;
}
}
DataTable の代わりに DataGridView に表示する・・⑧
上記④は読込したデータを DataTable
にセットしましたが、代わりに DataGridView
にセットします。
参考:【C#入門】DataGridViewの使い方(行の追加・削除、ソートも解説) | 侍エンジニアブログ
前略
cmd.CommandText = "SELECT TOP 5 * FROM titles;"; // ↑ここまで同じ
SqlDataReader dr = cmd.ExecuteReader(); // クエリを実行
dataGridView1.Columns.Clear(); // 必要
dataGridView1.Rows.Clear();
dataGridView1.Columns.Add("title_id","title_id"); // 列を追加
dataGridView1.Columns.Add("title", "title");
dataGridView1.Columns.Add("price", "price");
dataGridView1.Columns.Add("pubdate", "pubdate");
try
{
while (dr.Read()) // 一行ずつ読込
{
int n = dataGridView1.Rows.Add(); // 行を追加
DataGridViewRow row = dataGridView1.Rows[n];
row.Cells["title_id"].Value = dr["title_id"];
row.Cells["title"].Value = dr["title"];
row.Cells["price"].Value = dr["price"];
row.Cells["pubdate"].Value = dr["pubdate"];
}
}
後略
省略しないコード
private void button8_Click(object sender, EventArgs e)
{
textBox0.Clear();
textBox1.Clear();
try
{
SqlConnection cn = new SqlConnection();
cn.ConnectionString = conStr;
cn.Open();
textBox0.Text = "Connected.";
try
{
SqlCommand cmd = new SqlCommand();
cmd.Connection = cn;
cmd.CommandText = "SELECT TOP 5 * FROM titles;";
SqlDataReader dr = cmd.ExecuteReader(); // クエリを実行
dataGridView1.Columns.Clear(); // 必要
dataGridView1.Rows.Clear();
dataGridView1.Columns.Add("title_id", "title_id"); // 列を追加
dataGridView1.Columns.Add("title", "title");
dataGridView1.Columns.Add("price", "price");
dataGridView1.Columns.Add("pubdate", "pubdate");
try
{
while (dr.Read()) // 一行ずつ読込
{
int n = dataGridView1.Rows.Add(); // 行を追加
DataGridViewRow row = dataGridView1.Rows[n];
row.Cells["title_id"].Value = dr["title_id"];
row.Cells["title"].Value = dr["title"];
row.Cells["price"].Value = dr["price"];
row.Cells["pubdate"].Value = dr["pubdate"];
}
}
finally
{
dr.Close();
}
}
finally
{
cn.Close();
}
}
catch (Exception ex)
{
textBox0.Text = "Error:" + ex.Message;
}
}
DataTable
は列が データ型
属性を持っていましたが、DataGridView
はセルにセットされた値にデータ型が指定できます。
今回は指定しないで値をセットしています。デフォルトで Object
型になるようです。
参考:C# dataGridViewとキャストと型変換のあれこれ - プログラミング素人のはてなブログ
DataTable の内容を DataGridView に表示する・・⑨
データをセットした DataTable
の内容を DataGridView
に DataSource
プロパティを使って表示します。
参考:C#でのDataGridViewデータバインド完全解説: 効率的なデータ操作方法 | フリーランスチャンス
前略
cmd.CommandText = "SELECT * FROM sales;";
SqlDataReader dr = cmd.ExecuteReader(); // クエリを実行
DataTable dt = new DataTable(); // DataTable を用意
try
{
dt.Load(dr); // データを読込
}
finally
{
dr.Close();
} // ↑ここまで同じ
dataGridView1.Columns.Clear(); // 必要
dataGridView1.Rows.Clear();
dataGridView1.DataSource = dt; // ループで処理する代わり
後略
省略しないコード
private void button9_Click(object sender, EventArgs e)
{
textBox0.Clear();
textBox1.Clear();
try
{
SqlConnection cn = new SqlConnection();
cn.ConnectionString = conStr;
cn.Open();
textBox0.Text = "Connected.";
try
{
SqlCommand cmd = new SqlCommand();
cmd.Connection = cn;
cmd.CommandText = "SELECT * FROM sales;";
SqlDataReader dr = cmd.ExecuteReader(); // クエリを実行
DataTable dt = new DataTable(); // DataTable を用意
try
{
dt.Load(dr); // データを読込
}
finally
{
dr.Close();
}
}
finally
{
cn.Close();
}
dataGridView1.Columns.Clear(); // 必要
dataGridView1.Rows.Clear();
dataGridView1.DataSource = dt; // ループで処理する代わり
}
catch (Exception ex)
{
textBox0.Text = "Error:" + ex.Message;
}
}
DataReader
でテーブルの列のデータ型を取得して DataTable
の列に設定され、それが DataGridView
のセルの値に設定されるようです。
上記のコードで「qty」列は Int16
、「ord_date」列は DateTime
になっていました。
DataTable の内容を DataGridView に表示する・・⑩
上記⑨の DataTable
オブジェクトをメソッドの外側で宣言します。データがセットされたこのオブジェクトを、下記⑪など別のメソッドで参照したいからです。
private DataTable dt1 = new DataTable(); // メソッドの外側で宣言
private void button10_Click(object sender, EventArgs e)
{
中略
cmd.CommandText = "SELECT * FROM sales;";
SqlDataReader dr = cmd.ExecuteReader(); // クエリを実行
dt1.Clear(); // 必要
try
{
dt1.Load(dr); // データを読込
}
finally
{
dr.Close();
}
dataGridView1.Columns.Clear(); // 必要
dataGridView1.Rows.Clear();
dataGridView1.DataSource = dt1; // ループで処理する代わり
後略
省略しないコード
private DataTable dt1 = new DataTable(); // メソッドの外側で宣言
private void button10_Click(object sender, EventArgs e)
{
textBox0.Clear();
textBox1.Clear();
try
{
SqlConnection cn = new SqlConnection();
cn.ConnectionString = conStr;
cn.Open();
textBox0.Text = "Connected.";
try
{
SqlCommand cmd = new SqlCommand();
cmd.Connection = cn;
cmd.CommandText = "SELECT * FROM sales;";
SqlDataReader dr = cmd.ExecuteReader(); // クエリを実行
dt1.Clear(); // 必要
try
{
dt1.Load(dr); // データを読込
}
finally
{
dr.Close();
}
dataGridView1.Columns.Clear(); // 必要
dataGridView1.Rows.Clear();
dataGridView1.DataSource = dt1; // ループで処理する代わり
}
finally
{
cn.Close();
}
}
catch (Exception ex)
{
textBox0.Text = "Error:" + ex.Message;
}
}
ここで宣言した「dt1」を「DataGridView1」とバインドするのは、事前に実行してもいいでしょう。
private void Form1_Load(object sender, EventArgs e)
{
DataGridView1.DataSource = dt1;
}
private void button10_Click(object sender, EventArgs e)
{
中略
// dataGridView1.Columns.Clear();
// dataGridView1.Rows.Clear();
// dataGridView1.DataSource = dt1;
DataTable を操作する・・⑪
上記⑩で用意した DataTable
オブジェクト「dt1」に対して操作します。
まず、行を追加してみます。
参考:【C#】データテーブルの行の追加の方法 - Fun Coding
try
{
DataRow row = dt1.NewRow();
row["stor_id"] = "8042";
row["ord_num"] = "99999999";
row["ord_date"] = DateTime.Today;
row["qty"] = 9;
row["payterms"] = "on invoice";
row["title_id"] = "TC7777";
dt1.Rows.Add(row); // 行を追加
}
catch (Exception ex)
{
textBox0.Text = "Error:" + ex.Message;
}
続いて、指定した行のデータを変更してみます。
try
{
DataRow row = dt1.Rows[1]; // 2 行目を指定
row["qty"] = 9; // 変更する
}
catch (Exception ex)
{
textBox0.Text = "Error:" + ex.Message;
}
続いて、指定した行を削除してみます。
参考:【C#】データテーブルの行の削除の方法 - Fun Coding
try
{
DataRow row = dt1.Rows[3]; // 4 行目を指定
row.Delete(); // 行を削除
}
catch (Exception ex)
{
textBox0.Text = "Error:" + ex.Message;
}
DataGridView
オブジェクトにバインドしているので、操作した結果でグリッドの内容が変化します。
逆に、グリッドで操作して変更すると、DataTable
オブジェクトの内容が変化します。
アプリのメモリ上で展開されている DataTable
オブジェクトの内容が変更されただけなので、データベースの内容は変更されていません。
省略しないコード
private void button11_Click(object sender, EventArgs e)
{
textBox0.Clear();
textBox1.Clear();
try
{
DataRow row = dt1.NewRow();
row["stor_id"] = "8042";
row["ord_num"] = "99999999";
row["ord_date"] = DateTime.Today;
row["qty"] = 9;
row["payterms"] = "on invoice";
row["title_id"] = "TC7777";
dt1.Rows.Add(row); // 行を追加
}
catch (Exception ex)
{
textBox0.Text = "Error:" + ex.Message;
}
try
{
DataRow row = dt1.Rows[1];
row["title_id"] = "999999"; // 変更する
}
catch (Exception ex)
{
textBox0.Text = "Error:" + ex.Message;
}
try
{
DataRow row = dt1.Rows[3];
row.Delete(); // 行を削除
}
catch (Exception ex)
{
textBox0.Text = "Error:" + ex.Message;
}
}
DataTable の変更を確認する・・⑫
上記⑩で用意した DataTable
オブジェクト「dt1」に対して操作します。
行ごとの RowState
を確認してみます。
参考:.NET の DataTable の行の編集状態(RowState)の変化についてのまとめ #C# - Qiita
foreach (DataRow row in dt1.Rows) // 一行ずつ処理
{
textBox1.AppendText($"{row.RowState}\r\n"); // 行の状態を表示
}
省略しないコード
private void button12_Click(object sender, EventArgs e)
{
textBox0.Clear();
textBox1.Clear();
foreach (DataRow row in dt1.Rows) // 一行ずつ処理
{
textBox1.AppendText($"{row.RowState}\r\n"); // 行の状態を表示
}
}
DataTable の変更でデータベースを更新する・・⑬
上記⑩で用意した DataTable
オブジェクト「dt1」に対して操作します。
上記⑦のコードを応用します。行ごとに RowState
に応じてクエリを変えて実行します。
前略
SqlCommand cmd = new SqlCommand();
cmd.Connection = cn;
SqlTransaction tx = cn.BeginTransaction();
cmd.Transaction = tx;
try
{
foreach (DataRow row in dt1.Rows) // 一行ずつ処理
{
switch (row.RowState) // 行の状態に従って
{
case DataRowState.Unchanged: // 変更なし
continue;
case DataRowState.Modified: // 変更された
cmd.CommandText = "UPDATE sales " +
$" SET ord_date = '{row["ord_date"]}', qty = {row["qty"]}, payterms = '{row["payterms"]}', title_id = '{row["title_id"]}' " +
$" WHERE stor_id = '{row["stor_id"]}' AND ord_num = '{row["ord_num"]}';";
break;
case DataRowState.Added: // 追加された
cmd.CommandText = "INSERT INTO sales (stor_id, ord_num, ord_date, qty, payterms, title_id) " +
$" VALUES ('{row["stor_id"]}', '{row["ord_num"]}', CAST(CURRENT_TIMESTAMP AS DATE), {row["qty"]}, '{row["payterms"]}', '{row["title_id"]}');";
break;
case DataRowState.Deleted: // 削除された
cmd.CommandText = "DELETE FROM sales " +
$" WHERE stor_id = '{row["stor_id", DataRowVersion.Original]}' AND ord_num = '{row["ord_num",DataRowVersion.Original]}';";
break;
}
cmd.ExecuteNonQuery(); // クエリを実行
}
tx.Commit();
textBox1.Text = "Executed.";
}
catch
{
tx.Rollback();
throw;
}
後略
省略しないコード
private void button13_Click(object sender, EventArgs e)
{
textBox0.Clear();
textBox1.Clear();
try
{
SqlConnection cn = new SqlConnection();
cn.ConnectionString = conStr;
cn.Open();
textBox0.Text = "Connected.";
try
{
SqlCommand cmd = new SqlCommand();
cmd.Connection = cn;
SqlTransaction tx = cn.BeginTransaction();
cmd.Transaction = tx;
try
{
foreach (DataRow row in dt1.Rows) // 一行ずつ処理
{
switch (row.RowState) // 行の状態に従って
{
case DataRowState.Unchanged: // 変更なし
continue;
case DataRowState.Modified: // 変更された
cmd.CommandText = "UPDATE sales " +
$" SET ord_date = '{row["ord_date"]}', qty = {row["qty"]}, payterms = '{row["payterms"]}', title_id = '{row["title_id"]}' " +
$" WHERE stor_id = '{row["stor_id"]}' AND ord_num = '{row["ord_num"]}';";
break;
case DataRowState.Added: // 追加された
cmd.CommandText = "INSERT INTO sales (stor_id, ord_num, ord_date, qty, payterms, title_id) " +
$" VALUES ('{row["stor_id"]}', '{row["ord_num"]}', CAST(CURRENT_TIMESTAMP AS DATE), {row["qty"]}, '{row["payterms"]}', '{row["title_id"]}');";
break;
case DataRowState.Deleted: // 削除された
cmd.CommandText = "DELETE FROM sales " +
$" WHERE stor_id = '{row["stor_id", DataRowVersion.Original]}' AND ord_num = '{row["ord_num", DataRowVersion.Original]}';";
break;
}
cmd.ExecuteNonQuery(); // クエリを実行
}
tx.Commit();
textBox1.Text = "Executed.";
}
catch
{
tx.Rollback();
throw;
}
}
finally
{
cn.Close();
}
}
catch (Exception ex)
{
textBox0.Text = "Error:" + ex.Message;
}
}
DataAdapter でデータベースから読込する・・⑭
DataTable
の Load()
の代わりに、DataAdapter
の Fill()
を使います。上記⑨のコードを書換してみます。
参考:SqlDataReader と SqlDataAdapter の違いと使い分け - C# とデータベース - C# 入門
Fill()
の時点でデータベースと接続するようです。事前に Open()
する必要ありません。SqlConnection
オブジェクトを用意して DataAdapter
に渡しておきます。
参考:「[VB.NET]ADO.NETのコネクションとデータアダプタの関係について」(1) Insider.NET - @IT
前略
SqlConnection cn = new SqlConnection();
cn.ConnectionString = conStr;
// cn.Open(); // 不要
SqlCommand cmd = new SqlCommand();
cmd.Connection = cn;
cmd.CommandText = "SELECT * FROM sales;"; // ↑ここまで同じ
SqlDataAdapter da = new SqlDataAdapter(); // DataAdapter を用意
da.SelectCommand = cmd;
DataTable dt = new DataTable(); // DataTable を用意
da.Fill(dt); // ここで読込
textBox0.Text = "Connected.";
dataGridView1.Columns.Clear(); // 必要
dataGridView1.Rows.Clear();
dataGridView1.DataSource = dt; // ここで表示
// cn.Close(); // 不要
後略
省略しないコード
private void button14_Click(object sender, EventArgs e)
{
textBox0.Clear();
textBox1.Clear();
try
{
SqlConnection cn = new SqlConnection();
cn.ConnectionString = conStr;
// cn.Open(); // 不要
SqlCommand cmd = new SqlCommand();
cmd.Connection = cn;
cmd.CommandText = "SELECT * FROM sales;";
SqlDataAdapter da = new SqlDataAdapter(); // DataAdapter を用意
da.SelectCommand = cmd;
DataTable dt = new DataTable(); // DataTable を用意
da.Fill(dt); // ここで読込
textBox0.Text = "Connected.";
// cn.Close(); // 不要
dataGridView1.Columns.Clear(); // 必要
dataGridView1.Rows.Clear();
dataGridView1.DataSource = dt; // ここで表示
}
catch (Exception ex)
{
textBox0.Text = "Error:" + ex.Message;
}
}
DataAdapter でデータベースから読込する・・⑮
DataAdapter
オブジェクトをメソッドの外側で宣言します。データを処理したこのオブジェクトを下記⑯など別のメソッドで参照したいからです。
上記⑩で用意した DataTable
オブジェクト「dt1」に対して操作します。
private SqlDataAdapter da1 = new SqlDataAdapter(); // メソッドの外側で宣言
private void button15_Click(object sender, EventArgs e)
{
中略
SqlCommand cmd = new SqlCommand();
cmd.Connection = cn;
cmd.CommandText = "SELECT * FROM sales;";
da1.SelectCommand = cmd;
dt1.Clear(); // 必要
da1.Fill(dt1); // ここで読込
dataGridView1.DataSource = dt1; // ここで表示
後略
省略しないコード
private SqlDataAdapter da1 = new SqlDataAdapter(); // メソッドの外側で宣言
private void button15_Click(object sender, EventArgs e)
{
textBox0.Clear();
textBox1.Clear();
try
{
SqlConnection cn = new SqlConnection();
cn.ConnectionString = conStr;
// cn.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = cn;
cmd.CommandText = "SELECT * FROM sales;";
da1.SelectCommand = cmd;
dt1.Clear(); // 必要
da1.Fill(dt1); // ここで読込される
textBox0.Text = "Connected.";
dataGridView1.DataSource = null; // 必要
dataGridView1.Columns.Clear();
dataGridView1.Rows.Clear();
dataGridView1.DataSource = dt1;
// cn.Close();
}
catch (Exception ex)
{
textBox0.Text = "Error:" + ex.Message;
}
}
DataAdapter の CommandText を設定する・・⑯
上記⑮の DataAdapter
オブジェクトに対して、DbCommandBuilder
から派生した SqlCommandBuilder
を使って CommandText
を設定します。設定した CommandText
は下記⑰の Update()
で使用されます。
SqlCommandBuilder cb = new SqlCommandBuilder();
cb.DataAdapter = da1;
DbCommandBuilder
は、DataAdapter
に設定された SelectCommand
の内容に従って、適切な「更新」「挿入」「削除」のクエリを自動で作成してくれます。どんなクエリが作成されたのか確認できます。
参考:第5回 データセットを使ったレコードの追加:基礎解説 ADO.NET基礎講座 ―初めての.NETデータベース・プログラミング―(3/3 ページ) - @IT
textBox1.AppendText($"InsertCommand:{cb.GetInsertCommand().CommandText}\r\n");
textBox1.AppendText($"UpdateCommand:{cb.GetUpdateCommand().CommandText}\r\n");
textBox1.AppendText($"DeleteCommand:{cb.GetDeleteCommand().CommandText}\r\n");
省略しないコード
private void button16_Click(object sender, EventArgs e)
{
textBox0.Clear();
textBox1.Clear();
SqlCommandBuilder cb = new SqlCommandBuilder();
cb.DataAdapter = da1;
textBox1.AppendText($"InsertCommand:{cb.GetInsertCommand().CommandText}\r\n");
textBox1.AppendText($"UpdateCommand:{cb.GetUpdateCommand().CommandText}\r\n");
textBox1.AppendText($"DeleteCommand:{cb.GetDeleteCommand().CommandText}\r\n");
}
DataAdapter でデータベースを更新する・・⑰
上記⑬はループで処理しましたが、代わりに DataAdapter
の Update()
を使います。
上記⑮の DataAdapter
オブジェクト「da1」を使って、上記⑩で用意した DataTable
オブジェクト「dt1」に対して操作します。
参考:DataAdapterのUpdateメソッドの仕組み。猫の気ままなC#日記
try
{
da1.Update(dt1); // ここで更新
textBox0.Text = "Updated.";
}
catch (Exception ex)
{
textBox0.Text = "Error:" + ex.Message;
}
省略しないコード
private void button17_Click(object sender, EventArgs e)
{
textBox0.Clear();
textBox1.Clear();
try
{
da1.Update(dt1); // ここで更新
textBox0.Text = "Updated.";
}
catch (Exception ex)
{
textBox0.Text = "Error:" + ex.Message;
}
}
SqlConnection
オブジェクトは、上記⑮で作成されて「da1」に紐づいて保持されています。データベースに接続するのは、Fill()
と同様に Update()
で実行されるので、コードに記述しません。
実行されるクエリは、上記⑯でセットされます。
諸々の処理が DataAdapter
に組込されているので、コードは短くなりますが、何が実行されているのか分かりづらくなっていますね。↑