− 12 MySQLを使ったアプリ(Connecter/netの不具合?)

  MySQLを利用したアプリを作成してみる。「なぜ、MySQLをつかうのか?」と聞かれそうだが、将来的にはPHPを使用する予定だからだ。その場合には、MySQLをデータベースとして使っておくのが妥当だろう。開発としてVisualBasic2005・データベースとしてxampp・接続用にMySQL Connecter/net5.2.5を用いた。メイン画面イメージ
 画面のイメージとして初期画面を右のような構成にしてみる。ボタンがたくさんついていて見づらいように思えるが とりあえず画面の表示と入力の状態を見るために簡易的に作ってあるので ご了承していただきたい。
 xamppのphpMyAdminを用いてgftデータベースを作成。照合順序はutf8-general-ciにしている。お客様情報用にuserテーブル、お届け先情報用にnotifyテーブル、商品用にsyohinテーブルの3つテーブルを作成。商品検索用にmasterデータベース(商品名の書かれているTMASTテーブル)を使用する。

 構想はこうだ。
1.お客様の電話番号を入力し、確認ボタン押し下げ。
2.入力された電話番号をuserテーブルから検索し、データセットを作成。これをDataGridViewのデータソースに設定し、画面を表示する。
3.表示されたお客情報を選択し お客様用のお届け先名をnotifyテーブルから検索し、データセットを作成。画面下部のDataGridViewのデータソースに設定し表示する。
4.表示されたお客様を選択し、商品登録を行うと 商品登録画面が出てきて、画面から商品コードと商品名・価格・数量を入力する。(勿論、情報が登録されていれば商品名・価格はマスターから取り出して表示する)

 書いてみればしごく単純であるが、テーブルの構成とインデックスの付け方、テーブル間の関連付けが難しい。どんな作りにするかという根幹の部分なので、こういう部分はxampp等で試行錯誤を繰り返してテストを行ってから 本番のマシンに移行して動かすのが良いように私などは考える。今回はとりあえず以下のようなテーブル構成とした。テーブルレイアウト
 始めに電話番号で検索するので、userの主キーはtelnoからにしている。以降は該当顧客の番号でお客様を検索するようにしている。同じ電話番号で二名以上のお客様がいる可能性があるのでこのようにしている。(事業所のような場所を想定している。)

 ソースを一部表示すると、以下のようになる。
・共通変数の部分(画面が2画面になるのでPublicで設定

Module mjlGsys
Public Wkhdr As String '起動ホルダー
Public Myhdr As String 'ホルダー指定
Public Setno As String '電話番号
Public Custm As String 'お客様名前
Public Umflg As Long '更新確認用
Public TEL_NO As String '電話番号
Public SEQ_NO As Integer 'シーケンス番号
Public NTEL_NO As String '電話番号
Public NSEQ_NO As Integer 'シーケンス番号
'MySQL接続文字列
Public MyconString As String = "server=localhost;user=root;password='';database=gft;Connect Timeout=5000;"
Public MyconString2 As String = "server=localhost;user=root;password='';database=master;Connect Timeout=5000;"

・メインの接続作成部分

Imports MySql.Data.MySqlClient
Public Class frmGsys
'SQL関連の定数宣言はフォーム間共通にしておく
Dim sqlDA As MySql.Data.MySqlClient.MySqlDataAdapter 'データアダプタ作成
Dim sqlCmdbldr As MySql.Data.MySqlClient.MySqlCommandBuilder 'SQL コマンド作成
Dim resultDS As DataSet 'データセットオブジェクト
'SQL関連の定数宣言はフォーム間共通にしておく
Dim sqlDA2 As MySql.Data.MySqlClient.MySqlDataAdapter 'データアダプタ作成
Dim sqlCmdbldr2 As MySql.Data.MySqlClient.MySqlCommandBuilder 'SQL コマ}ンド作成
Dim resultDS2 As DataSet 'データセットオブジェクト
'MySQL接続文字列
Dim MyParam As MySql.Data.MySqlClient.MySqlParameter
Dim MyParam2 As MySql.Data.MySqlClient.MySqlParameter
Dim MyParam3 As MySql.Data.MySqlClient.MySqlParameter
'データ確認用リーダー
Dim sqlCon As New MySql.Data.MySqlClient.MySqlConnection '接続の作成
Dim sqlCmd As MySql.Data.MySqlClient.MySqlCommand 'SQL コマ}ンド
Dim sqlDr As MySql.Data.MySqlClient.MySqlDataReader
Dim sqlCon2 As New MySql.Data.MySqlClient.MySqlConnection '接続の作成
Dim sqlCmd2 As MySql.Data.MySqlClient.MySqlCommand 'SQL コマ}ンド
Dim sqlDr2 As MySql.Data.MySqlClient.MySqlDataReader

・データアダプターの作成

Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
Timer1.Enabled = False
'お客様情報用接続の作成
Try
'DataAdapterオブジェクトの作成
sqlDA = New MySql.Data.MySqlClient.MySqlDataAdapter
Catch ex As Exception
End Try
'お届け先様情報用接続の作成
Try
'DataAdapterオブジェクトの作成
sqlDA2 = New MySql.Data.MySqlClient.MySqlDataAdapter
Catch ex As Exception
End Try
'
Call Clset1()
Call Msgset("始めにお客様情報を確認します。電話番号で確認しますので 番号を指定し確認のボタンを押して下さい")
TEL_NO = ""
End Sub

・画面への表示部分

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
TEL_NO = Me.TextBox1.Text
If TEL_NO = "" Then
MsgBox("始めに電話番号を入れてください。" & vbCrLf & vbCrLf & "はじめてのお客様の場合には、新規登録ボタンを
行って下さい", MsgBoxStyle.Critical, "確認")
Else
Call Msgset("電話番号" & TEL_NO & "にてお客様情報を確認しています。おまち下さい")
'データセットの作成
Call Mkdataset1()
Try
MyParam.Value = TEL_NO
sqlDA.Fill(resultDS, "user")
'
DataGridView1.DataSource = resultDS
DataGridView1.DataMember = "user"
'
DataGridView1.Columns(3).Width = 200
DataGridView1.Columns(4).Width = 200
DataGridView1.Columns(6).Visible = False
'
Application.DoEvents()
Catch ex As Exception
MessageBox.Show("お客様情報読込中にエラー。" & ex.Message)
Finally
Call clset2()
Call Msgset("お客様情報を確認しました。次の処理を行ってください")
End Try
End If
End Sub
----------------
Sub Mkdataset1()
'お客様情報用接続の作成
Try
If resultDS IsNot Nothing Then resultDS = Nothing
'DataSetオブジェクトの作成
resultDS = New DataSet()
'コマ}ンドを作成
sqlDA.SelectCommand = New MySqlCommand()
sqlDA.SelectCommand.CommandType = CommandType.Text
sqlDA.SelectCommand.CommandText = "select namae as お名前, telno as 電話番号, postal as 郵便番号," & _
" adds1 as 住所, adds2 as 住所, kname as カナ名, seqno" & _
" from user where telno=?tel_no order by seqno"
MyParam = sqlDA.SelectCommand.Parameters.Add("?tel_no", MySqlDbType.String)
sqlDA.SelectCommand.Connection = New MySqlConnection(MyconString)
Catch ex As Exception
MessageBox.Show(Err.Number & ":" & Err.Description)
End Try
End Sub

・更新部分

Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
Ret = MessageBox.Show("変更内容の登録を行います", "登録の確認", MessageBoxButtons.YesNo, MessageBoxIcon.Que
stion)
If Ret = vbYes Then
Try
'Update文の自動実行のためにCommandBuilderオブジェクトを作成-DataSetに対する更新結果をDBに反映
sqlCmdbldr = New MySql.Data.MySqlClient.MySqlCommandBuilder(sqlDA)
sqlDA.Update(resultDS, "user")
resultDS.AcceptChanges()
MessageBox.Show("レコードは更新されました")
Catch ex As Exception
MessageBox.Show(Err.Number & ":" & Err.Description)
End Try
End If
End Sub

・画面の初期化部分

Private Sub Button5_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button5.Click
Ret = MessageBox.Show("初期画面が指定されました。終了しますか?", "確認", MessageBoxButtons.OKCancel, Message
BoxIcon.Question, MessageBoxDefaultButton.Button2)
If Ret = vbCancel Then
Exit Sub
End If
Try
'Update文の自動実行のためにCommandBuilderオブジェクトを作成-DataSetに対する更新結果をDBに反映
sqlCmdbldr = New MySql.Data.MySqlClient.MySqlCommandBuilder(sqlDA)
sqlDA.Update(resultDS, "user")
'
resultDS.AcceptChanges()
'======2013/12/05
resultDS.Clear()
Catch ex As Exception
MessageBox.Show(Err.Number & ":" & Err.Description)
End Try
Try
'画面の初期化
DataGridView1.DataSource = Nothing
DataGridView1.DataMember = Nothing
'画面の初期化
DataGridView2.DataSource = Nothing
DataGridView2.DataMember = Nothing
Catch ex As Exception
End Try
TextBox1.Text = ""
IseRow = 0
Call Clset1()
Call Msgset("始めにお客様情報を確認します。電話番号で確認しますので 番号を指定し確認のボタンを押して下さい")
TEL_NO = ""
End Sub

 この他にも DataGridViewのIMEモード設定等も行っているが、省略している。PDFファイルも添付しているのでこちらも参考にしてもらいたい。
で、結論から言うとドツボにはまってしまいました。何故か?

  電話番号入力とお客様の検索・画面表示と更新は、問題なくできました。この画面から選択して送り先情報を入力するのも問題なく出来ます。入力したデータをphpMyAdminで確認し、問題なく登録されていました。ですが、どうしても一度登録済んだ後、画面を初期化して再度同じ電話番号を入力すると、検索できないのです。入力せず 画面で確認してから画面を初期化し、再度同じ番号を入れると 問題なく検索されるのですが。
 データセットはUpdateをかければ、正しく元のデータベースに書き込まれるはずです。実際に、phpMyAdminを見ると 正しく更新されています。何故??全く理由がわかりません。仕方が無いので あちこち直してはテスト、直してはテストを行うのですが、いっこうに改善する気配がありません。どうしちゃったの?って感じです。インターネットで調べてみますが、こんな事例はどこにも載っていないようです。

 こんな事をいつまでもやってられないので、放り出してしまいました。が、数日後に 「ひょっとしたらMySQLの問題かもしれないからSQLServerを使ってみようか?」という考えが浮かびました。
 同じものをVisualBasic2008ExpressEditionで作り直し、データベースはSQLServer2008ExpressEditionを使うように変更。データベースとテーブルを同じように作成して(プログラムは 最初のお客様情報を入力し 画面に出して更新する部分だけしか作りませんでしたが)テスト。そしたら、何の問題もなく画面が出てきました。色々なパターンでデータを入力したり、更新したりしても全く問題なく動作します。これこそ、どうしちゃったの?です。
 考えました。「以下の3つのどれかが原因だろう。」と。
 1.xamppを使ったのが良くない。直接CentosのMySQLサーバーに接続してみたらどうだろうか?
 2.VisualBasic2005ExpressEditionが悪い。VisualBasic2008ExpressEditionで作り直してみたら?
 3.ミドルウエァ(MySQL Connecter/netの障害)。最新のバージョンに変えてみたら?
それぞれ、試してみました。まず、1番。これは駄目。次に2番。これも駄目。最後に3番。これが駄目なら、根本的に処理を作り直さねばなりませんが。

 試してみたら、何の問題も無く動きました。VisualBasic2005ExpressEditionにXamppの環境でです。現在はMySQL-Connecter/netはバージョンが6.7.4だそうで、これをダウンロードし、インストールし直し プログラムの参照設定を新しいものに変更しただけで、問題なく動いたのです。こんな事もあるんですね。常に、最新のバージョンを使えるような環境を作っておいた方が良いのかもしれませんね。

 プログラムの内容を上のように書くと、インデントされていない為に読みづらくなってしまいます。この為、内容をPDF化したものをつけてあります。必要ならこちらを参照してみて下さい 。PDFファイル。ちなみに、このファイルはVisualBasic 2005 Expressの内容をLibreOffice.4.1のWriterに貼り付けし PDFにエクスポートしたものです。テキストコピー可の形で作成していますので、そのまま使用することも可能です。

 追伸です。
 今回、このように作ったきっかけは、ある伝票を見せられて「こんな風に データ出せないですか?・・」みたいな話がきっかけです。
 ところが、実際に調べてみたところは、以下のような状況でした。
× Aというお客様が Bという届け先に1という商品を、Cという届け先に2という商品を、・・・贈る。
○ Aというお客様が 1という商品をB・C・D・・・の届け先に贈る。
でした。これなら、もっと別な画面の方が使いやすいでしょう。もう少し詳しく調査しておいた方が良かった。
まあ、こういう事ってよくある話です。作りながら、使う人に確かめて開発を進める、アジャイルみたいなやり方を考えておいた方が良いんでしょうね。きっと。

「市民の目」トップページへ戻る