1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

.NET アプリでデータベースを操作する

Last updated at Posted at 2024-11-09

はじめに

.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)をフォームに配置します。

説明.png

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 で読込した内容をセットします。

参考:C# DataTable 使い方 | ひろにもブログ

            前略
                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 の内容を DataGridViewDataSource プロパティを使って表示します。

参考: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;
        }

続いて、指定した行のデータを変更してみます。

参考:DataTableを編集する。猫の気ままなC#日記

        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 でデータベースから読込する・・⑭

DataTableLoad() の代わりに、DataAdapterFill() を使います。上記⑨のコードを書換してみます。

参考: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() で使用されます。

参考:ADO.NET入門記-010 (CommandBuilderの使用(Insert,Update,Delete) (CommandBuilder, DataAdapter, Fill, 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 でデータベースを更新する・・⑰

上記⑬はループで処理しましたが、代わりに DataAdapterUpdate() を使います。
上記⑮の 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 に組込されているので、コードは短くなりますが、何が実行されているのか分かりづらくなっていますね。↑

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?