前提と準備
C#の記事
- C#でMySQLを使う - 1.開発環境インストール
- C#でMySQLを使う - 2.SELECT・画面表示
- C#でMySQLを使う - 3.追加更新と削除【この記事】
前回はVisual Studio 2019にMySQL Connectors .NETを用いて、とりあえずMySQLに接続して、SELECTを用いてデータの内容を画面に表示しました。今回はDBのデータそのものを変更を施します(˶ ・ᴗ・ )੭
環境
- OS:Windows 10 Pro
- 開発環境:Visual Studio 2019 (MySQL Connectors .NET利用)
- データベース:MySQL 5.7
MySQLサーバー
テスト用ユーザー:test (パスワード:test1)
データベース:manutest
テーブル名:testtb
id | name | memo | |
---|---|---|---|
型 | INT | VARCHAR(64) | VARCHAR(256) |
必須属性 | PRIMARY KEY | NOT NULL | 初期値NULL |
その他属性 | AUTO_INCREMENT | - | - |
前提
前回のように、Visual Studio 2019とMySQLをインストールし、かつMySQL Connectors .NETがインストールされていること(Visual Studioは自動でMySQL Connectorsのライブラリを認識してくれる)
作業手順
Visual Studio 2019でのコーディング
コンポーネント・コントロールの配置
今回はボタンを押下→MySQLでデータを拾ってくる→画面に表示
これに加えて、名前とメモを入力し、追加や更新などができるようにフォームを追加
右上のリストボックスを選択すると該当するIDが画面表示されるので、選択している際に該当IDの更新や削除ができるようになりますが、細かいUI制御までは触れません
WindowsのC#フォームのプロジェクトを新規作成し、Form1.csデフォルトで開きました
- 左上:データグリッド dataGridView1
- 右上:リストボックス2つ listBox1・listBox2
- 選択するとテキストボックス「idNum」に該当するIDを表示する
- 左下:SQLを読み込むボタン button1
- 右中央:名前入力 textBoxName・メモ入力 textBoxMemo
- 右下:選択中のID idNum・新規追加SQL実行 buttonAdd・更新SQL実行 buttonEdit・削除SQL実行 buttonDel
これらを貼り付けます。
データグリッドとリストボックスはSQLのデータを表示させるために配置しました
MySQL Connector .NETの参照を追加
MySQLインストール時と同じように、参照を追加していきます。
「アセンブリ」の中に実際自動で認識してくれるので、参照マネージャーで、右上の検索画面に「mysql」を入力すると、↑の画面のように「MySql.Data」が何行も出てくるので、とりあえず1つだけ、どれでもいいので選択して(行左にマウスを当てると出てくるチェックボックスをON)「OK」を選択すると…
「MySql.Data」が追加されました(*˘꒳˘*)
この中にMySQLを扱うC#オブジェクトが入っているのです。
ボタンクリック時のソースを記述する
今回も簡単のため、SQLの実行はボタンクリックで読み込むだけで、Form1.csのクリックイベント動作のみをコーディングしました。本来は規模が大きくなることがほとんどなので、formのボタンクリックではなく、独立したクラスに分けるケースがほとんどですが。。。
Form1.cs サンプルコード
usingSystem;usingSystem.Collections.Generic;usingSystem.Data;usingSystem.Windows.Forms;usingMySql.Data.MySqlClient;namespaceMySqlFormsTest{publicpartialclassForm1:Form{// 取得したデータのID一覧(フォーム内部変数)privateList<int>idNums;// 選択中のIDprivateintselId;// MySQL接続情報privatestringconnStr="server=127.0.0.1;user id=test;password=test1;database=manutest";publicForm1(){InitializeComponent();}/**
* 接続ボタン(MySQLサーバーに接続し、一覧データを取得する)
* */privatevoidbutton1_Click(objectsender,EventArgse){MySqlConnectionconn=newMySqlConnection(this.connStr);// 画面と内部変数を初期化listBox1.Items.Clear();listBox2.Items.Clear();this.idNums=newList<int>();selId=-1;idNum.Text="";buttonEdit.Enabled=false;buttonDel.Enabled=false;try{// 接続を開くconn.Open();// データを取得するテーブルDataTabletbl=newDataTable();// SQLを実行するMySqlDataAdapterdataAdp=newMySqlDataAdapter("SELECT id, name, memo FROM testtb",conn);dataAdp.Fill(tbl);// dataGridViewに表示させるdataGridView1.DataSource=tbl;// 実行結果を1行ずつ参照する場合for(inti=0;i<tbl.Rows.Count;i++){DataRowrow=tbl.Rows[i];// データ行// 右のリストボックスにアイテムを追加listBox1.Items.Add(row[1]);listBox2.Items.Add(row[2]);// 同時にIDを内部変数に追加this.idNums.Add((int)row[0]);}// 接続を閉じるconn.Close();}catch(MySqlExceptionmse){MessageBox.Show(mse.Message,"データ取得エラー",MessageBoxButtons.OK,MessageBoxIcon.Error);}}/**
* リストボックスの行を選択
*/privatevoidlistBox1_SelectedIndexChanged(objectsender,EventArgse){this.listBox_SelectedIndexChanged(sender,e);// 選択したIDを画面表示if(listBox1.SelectedIndex!=-1){this.selId=idNums[listBox1.SelectedIndex];idNum.Text=idNums[listBox1.SelectedIndex].ToString();}else{this.selId=-1;idNum.Text="";}}privatevoidlistBox2_SelectedIndexChanged(objectsender,EventArgse){this.listBox_SelectedIndexChanged(sender,e);// 選択したIDを画面表示if(listBox2.SelectedIndex!=-1){this.selId=idNums[listBox2.SelectedIndex];idNum.Text=idNums[listBox2.SelectedIndex].ToString();}else{this.selId=-1;idNum.Text="";}}privatevoidlistBox_SelectedIndexChanged(objectsender,EventArgse){// どちらかを選択していないと追加と削除が使えないif(listBox1.SelectedIndex!=-1||listBox2.SelectedIndex!=-1){buttonEdit.Enabled=true;buttonDel.Enabled=true;}else{buttonEdit.Enabled=false;buttonDel.Enabled=false;}}/**
* 新規追加ボタンを選択
*/privatevoidbuttonAdd_Click(objectsender,EventArgse){MySqlConnectionconn=newMySqlConnection(this.connStr);MySqlTransactiontrans=null;// 実行トランザクション// 新規追加のSQLコマンドstringsqlCmd=@"INSERT INTO testtb (name, memo) VALUES (@name, @memo)";// 追加クエリの開始MySqlCommandcmd=newMySqlCommand(sqlCmd,conn);try{// ステークホルダーのセットcmd.Parameters.AddWithValue("name",textBoxName.Text);cmd.Parameters.AddWithValue("memo",textBoxMemo.Text);cmd.Connection.Open();// 接続を開く// トランザクション監視開始trans=cmd.Connection.BeginTransaction(IsolationLevel.ReadCommitted);// SQL実行cmd.ExecuteNonQuery();// DBをコミットtrans.Commit();}catch(MySqlExceptionmse){trans.Rollback();// 例外発生時はロールバックMessageBox.Show(mse.Message,"データ追加エラー",MessageBoxButtons.OK,MessageBoxIcon.Error);}finally{// 接続はクローズするcmd.Connection.Close();}}/**
* 編集ボタンを選択
*/privatevoidbuttonEdit_Click(objectsender,EventArgse){MySqlConnectionconn=newMySqlConnection(this.connStr);MySqlTransactiontrans=null;// 実行トランザクション// 編集のSQLコマンドstringsqlCmd=@"UPDATE testtb SET name = @name, memo = @memo WHERE id = @id";// 編集クエリの開始MySqlCommandcmd=newMySqlCommand(sqlCmd,conn);try{// 選択中のIDを用いて、ステークホルダーのセットcmd.Parameters.AddWithValue("id",this.selId);cmd.Parameters.AddWithValue("name",textBoxName.Text);cmd.Parameters.AddWithValue("memo",textBoxMemo.Text);cmd.Connection.Open();// 接続を開く// トランザクション監視開始trans=cmd.Connection.BeginTransaction(IsolationLevel.ReadCommitted);// SQL実行cmd.ExecuteNonQuery();// DBをコミットtrans.Commit();}catch(MySqlExceptionmse){trans.Rollback();// 例外発生時はロールバックMessageBox.Show(mse.Message,"データ更新エラー",MessageBoxButtons.OK,MessageBoxIcon.Error);}finally{// 接続はクローズするcmd.Connection.Close();}}/**
* 削除ボタンを選択
*/privatevoidbuttonDel_Click(objectsender,EventArgse){MySqlConnectionconn=newMySqlConnection(this.connStr);MySqlTransactiontrans=null;// 実行トランザクション// 削除のSQLコマンドstringsqlCmd=@"DELETE FROM testtb WHERE id = @id";// 削除クエリの開始MySqlCommandcmd=newMySqlCommand(sqlCmd,conn);try{// 選択中のIDを用いて、ステークホルダーのセットcmd.Parameters.AddWithValue("id",this.selId);cmd.Connection.Open();// 接続を開く// トランザクション監視開始trans=cmd.Connection.BeginTransaction(IsolationLevel.ReadCommitted);// SQL実行cmd.ExecuteNonQuery();// DBをコミットtrans.Commit();}catch(MySqlExceptionmse){trans.Rollback();// 例外発生時はロールバックMessageBox.Show(mse.Message,"データ削除エラー",MessageBoxButtons.OK,MessageBoxIcon.Error);}finally{// 接続はクローズするcmd.Connection.Close();}}}}
まずフォームのC#ソースの内部変数として、MySQLのデータでどのIDを取得したかと、右上のリストボックスの項目に対応するIDはどれを選択しているのかを把握するため、Form1にprivate変数を追加しました
// 取得したデータのID一覧(フォーム内部変数)privateList<int>idNums;// 選択中のIDprivateintselId;
読み込むSQLを実行するボタンで「SELECT id, name, memo~」をbutton1_Click()内で実行していると思いますが、単に右上のリストボックスにピックアップするだけでなく、対応するIDを内部変数idNumsで受け持つコードも実装しました
// 実行結果を1行ずつ参照する場合for(inti=0;i<tbl.Rows.Count;i++){DataRowrow=tbl.Rows[i];// データ行// 右のリストボックスにアイテムを追加listBox1.Items.Add(row[1]);listBox2.Items.Add(row[2]);// 同時にIDを内部変数に追加this.idNums.Add((int)row[0]);}
row[0]が取得したデータのID番号ですが、そのままListにAdd()を実行するとObjectを暗黙的に変換できないエラーとなるため、(int)でキャストしました。
listBox1.SelectedIndexlistBox2.SelectedIndex
listBox1_SelectedIndexChanged()などで使っていますが、リストボックスの選択したインデックス番号(0で始まるもの)はこれを使っています(未選択の場合は-1)。選択するとidNumの選択中IDのフィールドに表示する仕組みを入れたんです。選択中のIDは内部変数に入れています。
this.selId=idNums[listBox1.SelectedIndex];
INSERTやUPDATEなどDBの内容を更新するSQLは、MySqlCommandを使ったんですが、こっちのほうがプレースホルダーが使いやすいので、SELECT以外はMySqlCommandを使いました。
stringsqlCmd=@"INSERT INTO testtb (name, memo) VALUES (@name, @memo)";MySqlCommandcmd=newMySqlCommand(sqlCmd,conn);
そして更新の際はトランザクションを使っています。例外が発生したときはいつもロールバックするようにしていますが、正直タイミングは考えるのは大変なので、今回は簡単で例外キャッチのみで;;
try{trans=cmd.Connection.BeginTransaction(IsolationLevel.ReadCommitted);cmd.ExecuteNonQuery();trans.Commit();}catch(MySqlExceptionmse){trans.Rollback();// 例外発生時はロールバック}
実行結果
今回は追加などのボタンに再読み込み機能がないので、追加などのボタンを押した後は「読み込み」ボタンを押して再表示させています(面倒ですが…)
最初に下の画像のようなデータがあるとして、IDが6のデータを更新すると…
「更新」→「読み込み」で、更新に成功しました(˶ ・ᴗ・ )੭
次はIDが5の「Testing」というデータを選択して消してみます
再度読み込みボタンを押して、これも削除成功しました!!
次回
Visual StudioでMySQLのデータがNULLの場合にハマったことがあるので、そっちについて追ってみます
参考文献
関連文献
- C#のMySQLでトランザクション使用する / C#でのトランザクションの実装について
- Symfoware Server アプリケーション開発ガイド(埋込みSQL編) - FUJITSU - / SQLのトランザクションとは何かの理解
- 【MySQL 5.1向けのもの】MySqlTransaction の使用 / C#でのトランザクション実装例
- IsolationLevel 列挙型 / C#でのトランザクションレベル - .NET API