トップ回答者
ADOXにて作成したデータベースとテーブルの型について

質問
-
visualbasicEE
windowsXP
お世話になっております。
現在、あらかじめ作成しておいたデータベース(.mdbファイル)を、windowsフォーム上のデータグリッドビューにバインドさせて編集後、更新をかけてみるのですが、
同時実行違反 : UpdateCommand によって、処理予定の 1 レコードのうち 0 件が処理されました。
と出てしまいました。
私の構想としては、windowsフォームに、データベース保存先(.mdbファイル)からバインドされたデータグリッドビューが配置されており、ボタン等でこのデータベース保存先のconnectionstringを変更させることにより、別にADOXにて作成されたデータベース(ここでいうデータベースとは、先の.mdbファイルと同じ構造のものです。)に保存させるというものです。
先に述べたようなエラーが出るということは、あらかじめ保存されているデータベーステーブルの型とADOXにて保存されたテーブルの型に違いがあると考えました。
そこで、データベーステーブルプロパティでの型表示とADOXでの型表示の対応方法を教えて頂きたいのです。
例)
ADOX 通常のプロパティ
.Columns.Append("Num", DataTypeEnum.adDouble) double
要するに主要型の表示方法がADOXであればどのようになるのでしょうか?
回答
-
みやり さんからの引用
そこで、データグリッドビューに下記コードのように対象となるADOXで作成されたデータベースを読み込みました。Private Sub Button29_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button29.Click
Dim Cn As New OleDb.OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" _
& TextBox27.Text & YearComboBox.Text & "\" & TextBox1.Text & ".mdb")Dim da3 As OleDb.OleDbDataAdapter = New OleDb.OleDbDataAdapter _
("SELECT * FROM meisai_master", Cn)
Dim cb3 As OleDb.OleDbCommandBuilder = New OleDb.OleDbCommandBuilder(da3)DataSet1 = New DataSet("main_master")
da3.Fill(DataSet1, "meisai_master")
Me.BindingSource1.DataSource = DataSet1
Me.BindingSource1.DataMember = "meisai_master"
Me.DataGridView1.DataSource = Me.BindingSource1
End Subこの状態でデータグリッドビューでデータの変更を行い、データベースへ書き戻せば、同時実行違反は発生しません。同時実行違反はデータアダプタを使うかどうかではありません。テーブルアダプタは内部でデータアダプタを利用してデータベースへ更新をかけています。
今回のご質問のポイントは同時実行制御についてです。コマンドビルダーによって自動生成されるSQL文は必ず同時実行制御を行うように生成されます。どのようにして同時実行制御を行うかは、以下のリンク先における「オプティミスティック同時実行制御」の「すべての値を保存するアプローチ」をご覧下さい。ADO.NET におけるデータ同時実行制御の概要
http://msdn2.microsoft.com/ja-jp/library/cs6hb8k4(VS.80).aspxみやり さんからの引用
そこで、自分でクエリを作成して更新をかけたいと思うのですが、テーブルアダプタを使用した時のクエリをそのまま活用できるでしょうか?そして、出来れば下記コードを利用したコーディングの方法を教えて頂ければ幸いです。
はい。コマンドビルダーを使わないようにして下さい。コマンドビルダーに自動生成させるかわりに、自分でSelectCommand, UpdateCommand, DeleteCommnadを作成し、それをデータアダプタに割り当ててしまいましょう。この作成例は以下にあります。この際、SQL文を手動で作成しなければなりませんが、もしわからなければ、テーブルアダプタが作成したクエリなどを参考にすることもできます。
また、これらのコマンドは「データアダプタの構成」によって自動生成することもできます。これを行うにはツールボックスからデータアダプタをフォームにドラッグし、そのデータアダプタを右クリックして表示される「データアダプタの構成」をクリックします。途中で詳細設定ボタンがありますので、Insert, Update文を作成するにチェックし、オプティミスティック同時実行制御を行うのチェックを外して下さい。
なお、ツールボックスにはデフォルトでデータアダプタは表示されていませんので、ツールボックスを右クリックして「アイテムの選択」をクリックすることにより追加して下さい。OleDbDataAdapter.UpdateCommand プロパティ
http://msdn2.microsoft.com/ja-jp/library/system.data.oledb.oledbdataadapter.updatecommand(VS.80).aspxみやり さんからの引用
削除をかけるとdeletecommandがうまく動作しないようなエラーが出ます。これって、クエリを指定していないからですよね!?
これだけではなんともわかりませんが、削除時も同時実行制御が働いているのではないでしょうか?
すべての返信
-
みやり さんからの引用 先に述べたようなエラーが出るということは、あらかじめ保存されているデータベーステーブルの型とADOXにて保存されたテーブルの型に違いがあると考えました。
同時実行違反とは、データベースから値を読み込み、その値を変更してデータベースに書き戻すまでの間に、他の誰かによってデータベースの値に変更が加えられている場合に発生します。
今回のケースはデータベースから値を読み、それを他のデータベースへ保存しようとしているわけですから、自分が先にデータベースから読み込んだ値が、今保存しようとしているデータベースには存在しません。したがって、同時実行違反になる可能性があります。
今回のケースで同時実行違反の制御をかける場合は、connectionstringを変更してデータベースを切り替えるのではなく、2つのデータベースからそれぞれ値を読み込んでおき、片方の値でもう一方の値を更新し、そこからデータベースへ書き戻せばうまくいくでしょう。
-
trapemiyaさんいつもありがとうございます。
確認のために質問させていただきます。
(私のデータベース作成構造)
1 あらかじめデータベース(meisai.mdbとします。)にテーブル(meisai_masterとします。)を作成しておきます。
2 windowsフォームに上記データベースのデータセットを追加し、meisai_masterdatagridviewをドラッグ配置させ、テーブルアダ プタを使用できるようにします。
(プログラムの一連の動作、デバッグモード)
1 ボタン等で、ADOXを用いてmeisai_masterと同じテーブル構造の新規テーブルを任意のディレクトリに作成しておきます。
2 コンストラクタ等で、connectionstringを目的のデータベース(1で作成したもの)に接続し、meisai_masterdatagridviewにmeisai_masterをバインドさせます。
3 meisai_masterdatagridviewにてデータを編集(追加、削除、修正)した後、meisai_masterTableadapterを使用して更新させます。
(結果)
データの追加等は可能ですが、修正等を行った場合、同時実行違反が起こる。
前スレのとおり、これらのようなことが起こっています。trapemiyaさんが言われる意味の解釈ですが、あらかじめ配置されたデータテーブル及びテーブルアダプタを使用して、新規テーブルに修正更新は不可能(2つのテーブルに同時に更新をかけることは無理)ということですよね!?
そこで、良案を頂いているのですが
「2つのデータベースからそれぞれ値を読み込んでおき、片方の値でもう一方の値を更新」
これについての解釈は、あらかじめ設定されているデータベース(ここではmeisai_masterdatagridview)とは別に編集用テーブル(ここでは、ADOXで作成したテーブル)を新規データグリッドビューに読込むということですよね!?
ただ、更新をかける場合meisai_masterTableadapterを用いる方法って使えるのでしょうか?
meisai.mdb ADOXで作成したデータベース
| |
meisaidataset dataset1
| |
meisaidatasetBindingsource dataset1Bindingsource
| |
meisai_masterdatagridview datagridview1
| |
meisai_masterTableadapterにてデータ更新できるのでしょうか?
-
みやり さんからの引用 trapemiyaさんが言われる意味の解釈ですが、あらかじめ配置されたデータテーブル及びテーブルアダプタを使用して、新規テーブルに修正更新は不可能(2つのテーブルに同時に更新をかけることは無理)ということですよね!?
新規テーブルへ更新する場合、同時実行制御を行うことはできません。なぜなら、同時実行制御を行う場合、更新前のデータを予め取得しておき、その値と現在のテーブルの値を比較することによって、更新先のデータが誰からも変更されていないことを確認する必要がありますが、新規テーブルを作成しただけでは、予めこの比較元のデータを取得していないからです。
ただ、今回、プログラムで新しいデータテーブルを作成するわけですから、そのデータテーブルをそのプログラムのみしか使用せず、更新によりデータ整合が崩れる恐れがないのであれば、同時実行制御を行う必要は全くありません。
みやり さんからの引用 これについての解釈は、あらかじめ設定されているデータベース(ここではmeisai_masterdatagridview)とは別に編集用テーブル(ここでは、ADOXで作成したテーブル)を新規データグリッドビューに読込むということですよね!?
新しいデータグリッドビューに読みこむ必要はありません。ADOXで作成したデータベースからデータテーブルにデータを読み込み、そのデータテーブルに対して更新をかけ、データアダプタでADOXで作成したデータベースへ書き戻します。
前述しましたように、同時実行制御を行わなければ、このような面倒なことを行う必要はありません。
meisai.mdb ADOXで作成したデータベース
| |
meisaidataset dataset1
| |
meisaidatasetBindingsource |
| |
meisai_masterdatagridview |
| |
+-----------------------------------> ADOXで作成したデータベースからデータを読み込んだデータテーブルに
対して更新をかける。
|
|
ADOXで作成したデータベースへデータアダプタにより書き戻す。 -
おっしゃるとおり、まわりくどい方法は止めて、データアダプタの方法で更新したいと思います。
そこで、データグリッドビューに下記コードのように対象となるADOXで作成されたデータベースを読み込みました。
Private Sub Button29_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button29.Click
Dim Cn As New OleDb.OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" _
& TextBox27.Text & YearComboBox.Text & "\" & TextBox1.Text & ".mdb")Dim da3 As OleDb.OleDbDataAdapter = New OleDb.OleDbDataAdapter _
("SELECT * FROM meisai_master", Cn)
Dim cb3 As OleDb.OleDbCommandBuilder = New OleDb.OleDbCommandBuilder(da3)DataSet1 = New DataSet("main_master")
da3.Fill(DataSet1, "meisai_master")
Me.BindingSource1.DataSource = DataSet1
Me.BindingSource1.DataMember = "meisai_master"
Me.DataGridView1.DataSource = Me.BindingSource1
End Subそして、編集後データベース更新をするコードが下記のとおりなんですが、以前別のスレッドでテーブル構造上、複雑なクエリで保存不可能と出たのでコマンドビルダーでは無理という回答を得ました。
そこで、自分でクエリを作成して更新をかけたいと思うのですが、テーブルアダプタを使用した時のクエリをそのまま活用できるでしょうか?そして、出来れば下記コードを利用したコーディングの方法を教えて頂ければ幸いです。
ちなみに単にデータを追加する分については、うまく動きましたが削除をかけるとdeletecommandがうまく動作しないようなエラーが出ます。これって、クエリを指定していないからですよね!?
Private Sub Button31_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button31.Click
Dim Cn As New OleDb.OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" _
& TextBox27.Text & YearComboBox.Text & "\" & TextBox1.Text & ".mdb")
Dim da3 As OleDb.OleDbDataAdapter = New OleDb.OleDbDataAdapter("SELECT * FROM meisai_master", Cn)
Dim cb3 As OleDb.OleDbCommandBuilderTry
Cn.Open()cb3 = New OleDb.OleDbCommandBuilder(da3)
Dim MeisaiTbl As DataTable = DataSet1.Tables("meisai_master")
Me.Validate()
Me.BindingSource1.EndEdit()da3.Update(MeisaiTbl)
Cn.Close()
MsgBox("保存しました。")
Catch ex As System.Exception
MessageBox.Show(ex.Message)
End Try
End Sub -
みやり さんからの引用
そこで、データグリッドビューに下記コードのように対象となるADOXで作成されたデータベースを読み込みました。Private Sub Button29_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button29.Click
Dim Cn As New OleDb.OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" _
& TextBox27.Text & YearComboBox.Text & "\" & TextBox1.Text & ".mdb")Dim da3 As OleDb.OleDbDataAdapter = New OleDb.OleDbDataAdapter _
("SELECT * FROM meisai_master", Cn)
Dim cb3 As OleDb.OleDbCommandBuilder = New OleDb.OleDbCommandBuilder(da3)DataSet1 = New DataSet("main_master")
da3.Fill(DataSet1, "meisai_master")
Me.BindingSource1.DataSource = DataSet1
Me.BindingSource1.DataMember = "meisai_master"
Me.DataGridView1.DataSource = Me.BindingSource1
End Subこの状態でデータグリッドビューでデータの変更を行い、データベースへ書き戻せば、同時実行違反は発生しません。同時実行違反はデータアダプタを使うかどうかではありません。テーブルアダプタは内部でデータアダプタを利用してデータベースへ更新をかけています。
今回のご質問のポイントは同時実行制御についてです。コマンドビルダーによって自動生成されるSQL文は必ず同時実行制御を行うように生成されます。どのようにして同時実行制御を行うかは、以下のリンク先における「オプティミスティック同時実行制御」の「すべての値を保存するアプローチ」をご覧下さい。ADO.NET におけるデータ同時実行制御の概要
http://msdn2.microsoft.com/ja-jp/library/cs6hb8k4(VS.80).aspxみやり さんからの引用
そこで、自分でクエリを作成して更新をかけたいと思うのですが、テーブルアダプタを使用した時のクエリをそのまま活用できるでしょうか?そして、出来れば下記コードを利用したコーディングの方法を教えて頂ければ幸いです。
はい。コマンドビルダーを使わないようにして下さい。コマンドビルダーに自動生成させるかわりに、自分でSelectCommand, UpdateCommand, DeleteCommnadを作成し、それをデータアダプタに割り当ててしまいましょう。この作成例は以下にあります。この際、SQL文を手動で作成しなければなりませんが、もしわからなければ、テーブルアダプタが作成したクエリなどを参考にすることもできます。
また、これらのコマンドは「データアダプタの構成」によって自動生成することもできます。これを行うにはツールボックスからデータアダプタをフォームにドラッグし、そのデータアダプタを右クリックして表示される「データアダプタの構成」をクリックします。途中で詳細設定ボタンがありますので、Insert, Update文を作成するにチェックし、オプティミスティック同時実行制御を行うのチェックを外して下さい。
なお、ツールボックスにはデフォルトでデータアダプタは表示されていませんので、ツールボックスを右クリックして「アイテムの選択」をクリックすることにより追加して下さい。OleDbDataAdapter.UpdateCommand プロパティ
http://msdn2.microsoft.com/ja-jp/library/system.data.oledb.oledbdataadapter.updatecommand(VS.80).aspxみやり さんからの引用
削除をかけるとdeletecommandがうまく動作しないようなエラーが出ます。これって、クエリを指定していないからですよね!?
これだけではなんともわかりませんが、削除時も同時実行制御が働いているのではないでしょうか? -
遅くなりました。
考え方自体がまずかったというか理解力が乏しかったようです。
同じテーブル構造であれば、異なるデータベースでも更新可能なのだという間違いを犯してしまったようです。
そこでtrapemiyaさんの言われたとおり、データグリッドビューには、ウィザード上ではバインディング等一切せず、ADOXで作成されたデータベースをコード上でバインドさせる方法にしました。
すると、削除等の修正でも無事更新をすることが可能になりました。
また、データアダプタを使用しようと思っていましたが、テーブルアダプタ自体に組み込まれているとのことでしたので、クエリ等の設定が簡単なテーブルアダプタにて更新する方法にしました。
本当にありがとうございました。
また、よろしくお願いします。