- ベストアンサー
ヘルプのSQLが動かない?!VB.NET+Access2000環境での同時実行違反の解決方法
- データ更新時の「同時実行違反」解決のため、MSのヘルプから処理方法を探し、書かれていたSQLをそのまま動かそうとしているのですが、何か抜けているのかビルドエラーになります。
- Ctype(ex.Row.ltem(0), String)と書かれているのですが、ex.Row に波下線が入り文法上の記述間違いのような指摘が出てくるのですが、Ctypeの構文がおかしいのでしょうか?
- エラーの箇所をなんとか特定したいと頑張っています。よろしくご助言をお願いします。
- みんなの回答 (6)
- 専門家の回答
質問者が選んだベストアンサー
WHERE 句に全部載せているのですね? こういった場合、オリジナルの値を保持していないと、WHERE句引数値に該当する値が、既にデータセット内部で変更されているために、値を更新できないと思います。 >>更新は、キー項目に変更をかけていませんか? >>そうでなければ、更新でこけているのは非常に不思議です >ここがよく理解できてないんです。 >「キー項目に変更をかける」とは? 更新前のオリジナル値を持っていない場合は、キー項目の編集はご法度です。 WHERE句に設定する値は、ヘンゼルとグレーテルが元の場所へ辿るために置いておいたパンくずのようなものです。 更新後の値が入ったデータセットを、ホイと渡しても、Update文に設定するWHERE句の条件値には、更新後の値が条件として使用されます。 したがって、元の値(更新すべき対象)が行方不明となります。 全ての更新前のオリジナル値を持っていなければ、キー項目の編集を不可にしておき、それを頼りに、更新対象のWHERE句に設定できます。 質問者さんは >キーは日報NO であれば 日報NOの編集は不可にし、WHERE句を日報NOだけにすることにより、更新が可能となります。 削除も同様で、WHERE句を日報NOだけにすることにより、可能となります。 >データセットが同じDsReport1なのでどちらのテーブルの日報NOも読み込まれて更新に行くのでしょうか? >でもどちらかをはずすと関連づけがうまくいかないのではないでしょうか。 質問者さんの当初のアダプタ.Updateは、引数にテーブルを指定しているので、指定したテーブルのみが更新対象です。 私の示した6回のUpdate()メソッド発行での方法は、個別のテーブルからデータロウ配列を取り出しておりますので、対象となるデータテーブル以外は参照いたしません。 それと気になったのですが、、、SQL文は「?」(クエッション)を利用しているのですか? 業務であれば、パラメータ系のクラスを利用し、データテーブルのどのカラムが、どのSQL文とリンクしているかを明示した方が、良いと思います。 もしoledbを利用しているなら、OleDb.OleDbParameterというのがあります。 SqlClientならSqlClient.SqlParameterもあります。 OleDbParameterで検索をしたら見易いサンプルがあったので張っておきます。 http://park5.wakwak.com/~weblab/clsDBIO.html
その他の回答 (5)
- 1050 円(@1050YEN)
- ベストアンサー率69% (477/687)
先ほどの例のテーブルが間違ったので、もう一度と。。。 '削除:サブ odaSub.Update(l_dtbSub.Select("", "", DataViewRowState.Deleted)) '削除:メイン odaMain.Update(l_dtbMain.Select("", "", DataViewRowState.Deleted)) '更新:メイン odaMain.Update(l_dtbMain.Select("", "", DataViewRowState.ModifiedCurrent)) '更新:サブ odaSub.Update(l_dtbSub.Select("", "", DataViewRowState.ModifiedCurrent)) '追加:メイン odaMain.Update(l_dtbMain.Select("", "", DataViewRowState.Added)) '追加:サブ odaSub.Update(l_dtbSub.Select("", "", DataViewRowState.Added))
- 1050 円(@1050YEN)
- ベストアンサー率69% (477/687)
各アダプタの DeleteCommand() UpdateCommand() InsertCommand() のSQL文と、それぞれのSQLへのパラメータが、正常に設定されていることを前提にお話いたします。 >'データベースを更新 >odaMain.Update(DsReport1, "T_メイン") >odaSub.Update(DsReport1,"T_サブ") これは削除の時は、親を先に消しこもうとしますよね。 削除の時は、先にサブを消さなければなりません。だから削除はこけます。 更新は、キー項目に変更をかけていませんか? そうでなければ、更新でこけているのは非常に不思議です、、、(アダプタのUpdateCommand.CommandTextや引数を要確認) データセットの変更値の反映は、メインとサブの追加/更新/削除を個別にUpdateをかける必要があります。 Dim l_dtbMain As DataTable = DsReport1.Tables("T_メイン") Dim l_dtbSub As DataTable = DsReport1.Tables("T_サブ") '削除:サブ odaSub.Update(l_dtbSub.Select("", "", DataViewRowState.Deleted)) '削除:メイン odaMain.Update(l_dtbMain.Select("", "", DataViewRowState.Deleted)) '更新:メイン odaMain.Update(l_dtbSub.Select("", "", DataViewRowState.ModifiedCurrent)) '更新:サブ odaSub.Update(l_dtbSub.Select("", "", DataViewRowState.ModifiedCurrent)) '追加:メイン odaMain.Update(l_dtbMain.Select("", "", DataViewRowState.Added)) '追加:サブ odaSub.Update(l_dtbMain.Select("", "", DataViewRowState.Added))
補足
>更新は、キー項目に変更をかけていませんか? >そうでなければ、更新でこけているのは非常に不思議です ここがよく理解できてないんです。 「キー項目に変更をかける」とは? 先ほどサブのupdateのSQLを載せましたが、字数制限で載せられなかったメインのSQLを書きます。(長くてすみません) ------------------------ UPDATE [T_メイン] SET 日報NO = ?, 日付 = ?, 指示NO = ?, 車番 = ?, 運転手 = ?, 管轄支店 = ?, 出発地 = ?, 出発時 = ?, 出発分 = ?, [発メーター] = ?, 天候 = ?, 到着地 = ?, 到着時 = ?, 到着分 = ?, [着メーター] = ?, 給油地 = ?, 給油量 = ?, 給油支払額 = ?, 高速料金 = ?, その他料金 = ?, 特記事項 = ? WHERE (日報NO = ?) AND (その他料金 = ? OR ? IS NULL AND その他料金 IS NULL) AND (出発分 = ? OR ? IS NULL AND 出発分 IS NULL) AND (出発地 = ? OR ? IS NULL AND 出発地 IS NULL) AND (出発時 = ? OR ? IS NULL AND 出発時 IS NULL) AND (到着分 = ? OR ? IS NULL AND 到着分 IS NULL) AND (到着地 = ? OR ? IS NULL AND 到着地 IS NULL) AND (到着時 = ? OR ? IS NULL AND 到着時 IS NULL) AND (天候 = ? OR ? IS NULL AND 天候 IS NULL) AND (指示NO = ? OR ? IS NULL AND 指示NO IS NULL) AND (日付 = ? OR ? IS NULL AND 日付 IS NULL) AND (特記事項 = ? OR ? IS NULL AND 特記事項 IS NULL) AND ([発メーター] = ? OR ? IS NULL AND [発メーター] IS NULL) AND ([着メーター] = ? OR ? IS NULL AND [着メーター] IS NULL) AND (管轄支店 = ? OR ? IS NULL AND 管轄支店 IS NULL) AND (給油地 = ? OR ? IS NULL AND 給油地 IS NULL) AND (給油支払額 = ? OR ? IS NULL AND 給油支払額 IS NULL) AND (給油量 = ? OR ? IS NULL AND 給油量 IS NULL) AND (車番 = ? OR ? IS NULL AND 車番 IS NULL) AND (運転手 = ? OR ? IS NULL AND 運転手 IS NULL) AND (高速料金 = ? OR ? IS NULL AND 高速料金 IS NULL) ------------------------ キーは日報NOで両テーブルとも同じ名前です。 データセットが同じDsReport1なのでどちらのテーブルの日報NOも読み込まれて更新に行くのでしょうか? でもどちらかをはずすと関連づけがうまくいかないのではないでしょうか。
- 1050 円(@1050YEN)
- ベストアンサー率69% (477/687)
ありがとうございます。 >おかげさまでHELPからの情報はうまく動くようになりました。 ん?私のは、ヘルプのまま張ったようなもんですが・・・・ なぜ、うまくいかなかったのですか? こういう場合は、どこをどのように修正したかを公開しましょうね^^; 私が認識している状況は >Catch ex As DBConcurrencyException を利用していることから ・「アダプタを利用した更新」でこけている ということだけです。 追加/更新/削除のどれでこけているかもわかりませんが、いずれかのSQL文の設定が間違っているかも知れません。 キー項目を更新しようとしてこけているのかも知れません。 追加順序が、DBのリレーショナルに添わないで行われている。あるいは追加更新削除が一度で行われていて、その全ての更新順序が、DBのリレーショナルに添わないで行われようとしているのかも知れません。 とりあえず・・・・ >特におかしなところを見つけることができませんでした。 こういう場合、エラーが起きているのだから、そのアダプタ.Updateを行っている一連の処理を公開しないと。。。 これ以上の事は何も言えませんが。。。。
補足
たびたびありがとうございます。 >なぜ、うまくいかなかったのですか? >こういう場合は、どこをどのように修正したかを公開しましょうね^^; すみません。 深く考えていなかったもので・・・。 何をしたかというと、1050YENさんが示していただいたHELPをそのまま使ったと言うだけです。 なぜ前のが動かなかったかまで戻らなかったもので。 もう一点。 確かに断片的ではなく流れに沿った状況を示さないと解らないですよね。これも申し訳ありませんでした。 以下が今困っているルーティンです。 ------------------------ Private Sub mnuFileExit_Click(ByVal sender As Object, ByVal e As System.EventArgs)_ Handles mnuFileExit.Click '現在の編集を終了する Call ChkEdit() 'データベースを更新 odaMain.Update(DsReport1, "T_メイン") odaSub.Update(DsReport1,"T_サブ") 'アプリケーションを終了する Application.Exit() End Sub Private Sub ChkEdit() 'データグリッドの編集を終了する Me.BindingContext(DsReport1, "T_メイン.subNippo").EndCurrentEdit() End Sub ------------------------ 終了のボタンをクリックしたら編集を終了して、メインとサブの両DBにデータを更新に行く というストーリーなのですが、データグリッドを使用して表示させているサブのテーブルのみが編集できません。 このときに「同時実行違反」のエラーが出ます。 なお新規追加は問題なく実行できます。 削除と更新で引っかかります。 UPDATEのSQLは以下の通りです。 UPDATE [T_サブ] SET 荷主 = ?, 休憩時間 = ?, 作業時間 = ?, 運賃 = ?, 重量 = ?, 出発時 = ?, 出発分 = ?, 待ち時間 = ?, 地名 = ?, [着メーター] = ?, 到着時 = ?, 到着分 = ?, 特記事項 = ?, 日報NO = ?, 品名 = ? WHERE (荷主 = ?) AND (休憩時間 = ?) AND (作業時間 = ?) AND (運賃 = ?) AND (重量 = ?) AND (出発時 = ?) AND (出発分 = ?) AND (待ち時間 = ?) AND (地名 = ?) AND ([着メーター] = ?) AND (到着時 = ?) AND (到着分 = ?) AND (特記事項 = ?) AND (日報NO = ?) AND (品名 = ?) 実際のコードを編集せずに転記しましたのでわかりにくいかもしれませんが、変に細工をして問題を見えなくするよりもと思いましたのであえて載せました。 うまく動くインサートも必要であれば載せますのでご指示ください。 よろしくお願いいたします。
- 1050 円(@1050YEN)
- ベストアンサー率69% (477/687)
.NET2002ですが、今やってみました。 ヘルプのIDが異なるので、以下を参考に実験しました。 http://msdn.microsoft.com/library/ja/default.asp?url=/library/ja/Vbcon/html/vbtskCatchingConcurrencyError.asp Try アダプタ.Update() Catch ex As DBConcurrencyException Dim customErrorMessage As String customErrorMessage = "Concurrency violation" & vbCrLf customErrorMessage &= ex.Row(0).ToString MessageBox.Show(customErrorMessage) End Try 構文エラーは私のところでは発生しませんでした。 そして普通に、エラーが発生したレコードの先頭アイテムの情報が出力されました。。。 >構文が間違ってるぞ! というメッセージですよね。これは。 だとは思うのですが、、、 タスク一覧で、その構文がどようにまずいのかが出力されていると思います。 そちらを確認しましたか?
補足
ありがとうございます。 おかげさまでHELPからの情報はうまく動くようになりました。 表示されるConcurrency Violationは [データセット名+サブテーブル名Row] ということでどうも変更されたレコードの先頭で発生しているようです。 その後15列あるサブテーブルのデータを Row()とItem()で一つ一つ表示させてみましたが、特におかしなところを見つけることができませんでした。 次にやる手だて(チェック)はどのようにすれば良いでしょうか? ちなみに一番最初のデータはメインとサブを連携するキーフィールドです。 よろしくお願いします。
- 1050 円(@1050YEN)
- ベストアンサー率69% (477/687)
>Ctype(ex.Row.ltem(0), String) >ex.Row に波下線 exはデータテーブルですよね? Ctype(ex.Rows(0からのロウ番号を指定).ltem(0), String) ではだめですか?
補足
早速ありがとうございます。 投稿(質問)する前に試してみたのですが、Rows()でも Rowでも結果は同じでした。(括弧の中の数字はどれでも一緒) 構文が間違ってるぞ! というメッセージですよね。これは。 exは Catch ex As DBConcurrencyException という風にかかれています。
お礼
いろいろとご教示ありがとうございます。 あれから試行錯誤を繰り返していますが、まだ解決には至っておりません。 もう少しじっくりと考えて取り組んでみます。 ありがとうございました。