DOBON.NET DOBON.NETプログラミング掲示板過去ログ

oracleDataAdapterのUpdateメソッドでDBConcurrencyException: 同時実行違反が発生

環境/言語:[WindowsXP 使用言語:C++/CLI .NET Framework2.0 Oracle11g]
分類:[.NET]

お世話になります。

現在、OracleDataAdapterのFillメソッドにて、DBのデータをDataSetに格納し、それをプログラム上で編集し、OracleDataAdapterのUpdateメソッドによりDBに反映するプログラムを作成しております。

このプログラムで先日、
System.Data.DBConcurrencyException: 同時実行違反 : UpdateCommand によって、処理予定の 1 レコードのうち 0 件が処理されました。
とのエラーが発生しました。

調査してみたところ、更新対象のテーブルには上のプログラム以外は更新していない状況です。

また、上記のエラー発生時に、catchした中でRowプロパティを参照してみたところ、特に問題となる箇所は見当りませんでした。
(Rowプロパティで得られた値と全く同じ行がDB上にも存在し、なおかつ中の値も
同じものでありました。)

ちなみに、Updateで使用するコマンドは、CommandBuilderにて自動生成したものを使用し、更新対象は単一のテーブル、主キーは3つで、その中にはDATE型の列も含まれます。

なお、主キーの値はプログラム上では書き換えていないことは確認済みです。
(新規行の作成はありますが、問題となっているデータがDB上にも存在していることから、おそらくUpdateでのエラーと思われます。)

通常、本エラーは複数ユーザーの同時更新で発生するものと認識しますが、今回、複数ユーザーによる更新ということはありませんでした。
複数のユーザーが更新しているわけでもないのに上記エラーが発生することは有り得るのでしょうか?

何卒よろしくお願いします。
2009/08/21(Fri) 18:39:32 編集(投稿者)

■No25261に返信(gnw54さんの記事)
「VB 同時実行違反」でWEB検索すれば、かなり色んなパターンでこのエラーメッセージが
表示されることが分かります。単純にデータ更新に失敗しただけで出る可能性があります。
もちろん、自分自身が複数コネクション持っていて、本当に競合している場合もある
でしょう。
まずは、UpdateCommand にどんな SQL が自動生成されているのか出力して確認して
みては?自動生成の SQL には実行に必要な条件もあり、エラーも正しく出力されない
場合があったので、ボクはもう自分で SQL 文を編集して
OracleCommand.ExecuteNonQuery で実行してしまうことにしてしまいました。
今では自動生成は全く使っておりません。
■No25261に返信(gnw54さんの記事)
> 複数のユーザーが更新しているわけでもないのに上記エラーが発生することは有り得るのでしょうか?

あり得ます。

自動採番系のフィールドの取り扱いミスなど、幾つかの要因がありますが、自動生成された
パラメータの型が間違っていた場合や、自動生成された更新 SQL に問題があった場合には、
更新すべき対象レコードを発見できなくなる事が知られています。


> また、上記のエラー発生時に、catchした中でRowプロパティを参照してみたところ、特に問題となる箇所は見当りませんでした。
> (Rowプロパティで得られた値と全く同じ行がDB上にも存在し、なおかつ中の値も
> 同じものでありました。)
『Rowプロパティで得られた値』を取得する際には、DataRowVersion を指定して、
Original バージョンの値も併せて確認してみてください。

また、それぞれの値が UpdateCommand にパラメータとして渡される事になるわけですが、
それぞれのパラメータの定義が意図した物になっているかどうかも確認してみてください。


> System.Data.DBConcurrencyException: 同時実行違反 : UpdateCommand によって、処理予定の 1 レコードのうち 0 件が処理されました。
> とのエラーが発生しました。
まずは、UpdateCommand の内容を確認しておいてください。
特に、 CommandText と Parameters の内容についてです。


例えば、UpdateCommand として
 UPDATE table1 SET 社員番号 = 新しい社員番号, 氏名 = 新しい氏名, 登録日 = 新しい登録日
 WHERE 社員番号 = 元の社員番号 AND 氏名 = 元の氏名 AND 登録日 = 元の登録日
のような SQL が生成されていたとして、この時、「登録日」のデータが、
System.Data.DbType.DateTime ではなく System.Data.DbType.Date として
マッピングされていたとすれば、更新処理の段階で、System.DateTime の時刻部が
抜け落ちてしまうことになります。

そのため、WHERE 登録日 = 元の登録日 という問い合わせが、たとえば本来の
『2009/08/21 17:40:10』ではなく『2009/08/21』という値で行われる事になり、
処理予定のレコードがヒットしなくなります。そのまま更新処理を続行すれば、
> 処理予定の 1 レコードのうち 0 件が処理されました。
というエラーを生じる事になります。


あとは、主キー項目の扱いにも注意が必要です。

複数レコードに対して主キーの更新処理を行うと、処理の順序によっては
今回の DBConcurrencyException が発生することがありますので。
るしぇさん、魔界の仮面弁士さん、どうもありがとうございました。

本エラーの原因が判明致しました。
マスター設定ミスにより、複数のPCから同一データを更新しておりました。
たいへんお騒がせ致しました・・・。

なお、今回の原因究明にあたっては、
>『Rowプロパティで得られた値』を取得する際には、DataRowVersion を指定して、
>Original バージョンの値も併せて確認してみてください。
で教えていただきましたように、上記の比較がとても役に立ちました。

どうもありがとうございました。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板