C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[4]: オプティミスティック同時実行制御 Insert処理


(過去ログ 44 を表示中)

[トピック内 12 記事 (1 - 12 表示)]  << 0 >>

■23608 / inTopicNo.1)  オプティミスティック同時実行制御 Insert処理
  
□投稿者/ yan (5回)-(2008/08/19(Tue) 11:10:48)

分類:[.NET 全般] 

VS2005
Oracle10g

System.Data.Common.DbDataAdapterのUpdateメソッドでDataTableの変更をDBへ反映する際
UpdateとDeleteについてはDbCurrencyExceptionで同時実行制御違反をキャッチすることができます。

Insert処理の場合、他ユーザにより既に追加されていた場合、一意制約違反としてOracleExceptionが発生しますが
OracleExceptionをキャッチしても、実際に一意制約違反かどうかは判断できません。

Insert処理を行う際に、他ユーザにより既に追加されていた場合は、同時実行制御違反としてユーザに通知し処理を続行したいのですが
どのような方法があるかご教示ください。

よろしくお願いいたします。

引用返信 編集キー/
■23609 / inTopicNo.2)  Re[1]: オプティミスティック同時実行制御 Insert処理
□投稿者/ カドルドエグ (12回)-(2008/08/19(Tue) 11:22:50)
2008/08/19(Tue) 11:34:55 編集(投稿者)
2008/08/19(Tue) 11:32:52 編集(投稿者)

<pre><pre>■No23608 (yan さん) に返信
> VS2005
> Oracle10g
>
> System.Data.Common.DbDataAdapterのUpdateメソッドでDataTableの変更をDBへ反映する際
> UpdateとDeleteについてはDbCurrencyExceptionで同時実行制御違反をキャッチすることができます。
>
> Insert処理の場合、他ユーザにより既に追加されていた場合、一意制約違反としてOracleExceptionが発生しますが
> OracleExceptionをキャッチしても、実際に一意制約違反かどうかは判断できません。
>
> Insert処理を行う際に、他ユーザにより既に追加されていた場合は、同時実行制御違反としてユーザに通知し処理を続行したいのですが
> どのような方法があるかご教示ください。
>
> よろしくお願いいたします。
>

泥臭い(?)方法ならば、
事前にインサート先のテーブル内をforなどで回し、
キーとなる入力値とテーブルに登録されているキー項目の値を比較して、
それが一致していたら「既に登録されています」などのメッセージを出す、
といったところでしょうか。

<<追記:サンプルコード>>
※言語が書いてなかったので勝手ながらC#

private bool IsValidHoge(キーとなる入力値)
{
for(int i ; i = 0 ;i++)
{
チェックされる行 = インサート先のテーブル[i];
if(チェックされる行.キー項目 == キーとなる入力値) return false; // 異常を発見次第Falseを返す
}

// 異常がなければfor文を抜け =「異常無し」
return true;
}


private void UpdateHoge()
{
if(!IsValid(キーとなる入力値))
{
MessageBox.Show("既に登録されています");
}
else
{
try
{
更新
}
catch(Exception e)
{
MessageBox.Show("エラーが発生しました。");
}
}
}</pre></pre>
引用返信 編集キー/
■23611 / inTopicNo.3)  Re[1]: オプティミスティック同時実行制御 Insert処理
□投稿者/ 魔界の仮面弁士 (822回)-(2008/08/19(Tue) 11:42:07)
No23608 (yan さん) に返信
> VS2005
> Oracle10g
手元に環境が無いので確認できてはいませんが:

> OracleExceptionをキャッチしても、実際に一意制約違反かどうかは判断できません。

OracleException の例外から、"ORA-00001" 等の情報は得られないでしょうか?

System.Data.OracleClient なら ex.Code とか、ex.Message とか。
Oracle.DataAccess なら、ex.Code とか、あるいは foreach(OracleError er in ex.Errors) して、
er.Code とか er.ArrayBindIndex とか。
引用返信 編集キー/
■23614 / inTopicNo.4)  Re[2]: オプティミスティック同時実行制御 Insert処理
□投稿者/ yan (7回)-(2008/08/19(Tue) 11:46:41)
Insert文を投げたときに制約違反になったら例外が出力されるので、例外情報から一意制約違反かどうかを判断できればと思っています。

一意制約違反の場合、OracleExceptionのCodeプロパティが1であることが今わかりました。
ただSystem.Data.Common名前空間を使っているのでSystem.Data.DbExceptionでキャッチしたいのですが
System.Data.DbExceptionではCodeプロパティが無いようで、現在煮詰まっております。
引用返信 編集キー/
■23615 / inTopicNo.5)  Re[2]: オプティミスティック同時実行制御 Insert処理
□投稿者/ yan (9回)-(2008/08/19(Tue) 11:53:18)
No23611 (魔界の仮面弁士 さん) に返信
> ■No23608 (yan さん) に返信
>>VS2005
>>Oracle10g
> 手元に環境が無いので確認できてはいませんが:
>
>>OracleExceptionをキャッチしても、実際に一意制約違反かどうかは判断できません。
>
> OracleException の例外から、"ORA-00001" 等の情報は得られないでしょうか?
>
> System.Data.OracleClient なら ex.Code とか、ex.Message とか。
> Oracle.DataAccess なら、ex.Code とか、あるいは foreach(OracleError er in ex.Errors) して、
> er.Code とか er.ArrayBindIndex とか。

OracleExceptionでキャッチしてex.codeで判断するか
DbExceptionでキャッチしてex.messageの"ORA-00001"で判断するか ということになりますね。
引用返信 編集キー/
■23616 / inTopicNo.6)  Re[3]: オプティミスティック同時実行制御 Insert処理
□投稿者/ 魔界の仮面弁士 (823回)-(2008/08/19(Tue) 12:35:21)
No23614 (yan さん) に返信
> 一意制約違反の場合、OracleExceptionのCodeプロパティが1であることが今わかりました。
つまり、"ORA-00001" であった、という事ですよね。

> ただSystem.Data.Common名前空間を使っているのでSystem.Data.DbExceptionでキャッチしたいのですが
キャッチできますよ。
OracleException は、DbException を継承していますので。

> System.Data.DbExceptionではCodeプロパティが無いようで、現在煮詰まっております。
キャストするとか。
引用返信 編集キー/
■23617 / inTopicNo.7)  Re[4]: オプティミスティック同時実行制御 Insert処理
□投稿者/ yan (11回)-(2008/08/19(Tue) 13:16:09)
No23616 (魔界の仮面弁士 さん) に返信
> ■No23614 (yan さん) に返信
>>一意制約違反の場合、OracleExceptionのCodeプロパティが1であることが今わかりました。
> つまり、"ORA-00001" であった、という事ですよね。
>
>>ただSystem.Data.Common名前空間を使っているのでSystem.Data.DbExceptionでキャッチしたいのですが
> キャッチできますよ。
> OracleException は、DbException を継承していますので。
>
>>System.Data.DbExceptionではCodeプロパティが無いようで、現在煮詰まっております。
> キャストするとか。

書き方が悪かったようです。すいません。
DbExceptionでOracleExceptionをキャッチすることはできますが
DbExceptionでキャッチすると、OracleExceptionにキャストする以外にCodeプロパティの値を取得できないです。
ただOracleからSQLServerに変更される可能性があるため、OracleExceptionがコードのあちこちに散らばるのは避けたいので
"ORA-00001"を定数にしておく方がDBが変更された際の、コード変更は少なくて済むかと考えています。

Const UNIQUE_ERR As String ="ORA-000001"
Dim adp As DbDataAdapter
Dim tbl As DataTable

中略

Try
adp.Update(tbl)
Catch ex As DbException
If ex.Message.IndexOf(UNIQUE_ERR) Then
Throw New DbCurrencyException(ex.message,ex)
Else
Throw
End If
End Try


DB更新があるたびに Catch句の内容を書くのも面倒なのでどうにか自作例外でできないかと思案中です。

引用返信 編集キー/
■23619 / inTopicNo.8)  Re[5]: オプティミスティック同時実行制御 Insert処理
□投稿者/ 魔界の仮面弁士 (824回)-(2008/08/19(Tue) 14:21:25)
2008/08/19(Tue) 14:24:11 編集(投稿者)

No23617 (yan さん) に返信
> ただOracleからSQLServerに変更される可能性があるため、
あえて System.Data.Common を使うという事は、最初にファクトリからインスタンスが生成されるわけですよね。
http://www.microsoft.com/japan/msdn/thisweek/300x10/Phase3/fact/vb.aspx

そのとき、現在の接続が Oracle なのか SQL Server なのか それ以外なのかといった情報を、どこかで
保持しておくのでしょうか? それとも、DB の違いは一切意識させたくないのでしょうか?

> OracleExceptionがコードのあちこちに散らばるのは避けたいので
例外処理クラスを予め作っておき、それを呼び出してみては如何でしょうか。
他のデータベースに切り替えた際、必ずしも ex.Message から十分な情報が得られると言う保証は
無いので、今の実装だと、移植性が損なわれてしまうように思えます。

> Const UNIQUE_ERR As String ="ORA-000001"
これは避けたほうが良いかと思いますよ。
プロバイダを切り替えても対処できないので(再コンパイルが必要になってしまう)。

> DB更新があるたびに Catch句の内容を書くのも面倒なのでどうにか自作例外でできないかと思案中です。
Exception を引数に取り、Catch 句の内容を代替するための補助メソッドを用意するとか。
引用返信 編集キー/
■23630 / inTopicNo.9)  Re[6]: オプティミスティック同時実行制御 Insert処理
□投稿者/ yan (13回)-(2008/08/19(Tue) 16:33:09)
No23619 (魔界の仮面弁士 さん) に返信
> 2008/08/19(Tue) 14:24:11 編集(投稿者)
>
> ■No23617 (yan さん) に返信
>>ただOracleからSQLServerに変更される可能性があるため、
> あえて System.Data.Common を使うという事は、最初にファクトリからインスタンスが生成されるわけですよね。
> http://www.microsoft.com/japan/msdn/thisweek/300x10/Phase3/fact/vb.aspx
>
> そのとき、現在の接続が Oracle なのか SQL Server なのか それ以外なのかといった情報を、どこかで
> 保持しておくのでしょうか? それとも、DB の違いは一切意識させたくないのでしょうか?

自作のDbクラスで保持しています。

>>OracleExceptionがコードのあちこちに散らばるのは避けたいので
> 例外処理クラスを予め作っておき、それを呼び出してみては如何でしょうか。
> 他のデータベースに切り替えた際、必ずしも ex.Message から十分な情報が得られると言う保証は
> 無いので、今の実装だと、移植性が損なわれてしまうように思えます。

Accessで確認したところex.messageには一意制約違反と判断できるエラー番号がありませんでした。

>>Const UNIQUE_ERR As String ="ORA-000001"
> これは避けたほうが良いかと思いますよ。
> プロバイダを切り替えても対処できないので(再コンパイルが必要になってしまう)。
>
>>DB更新があるたびに Catch句の内容を書くのも面倒なのでどうにか自作例外でできないかと思案中です。
> Exception を引数に取り、Catch 句の内容を代替するための補助メソッドを用意するとか。

今は補助メソッドを用意する方法で検討しているのですが、Accessでは何を基準に一意制約違反と判断させればいいのか・・・
SQLServerではエラー番号2601ですが、ex.Messageに含まれるのか環境がないためわかりません。

引用返信 編集キー/
■23634 / inTopicNo.10)  Re[7]: オプティミスティック同時実行制御 Insert処理
□投稿者/ 魔界の仮面弁士 (825回)-(2008/08/19(Tue) 17:19:54)
No23630 (yan さん) に返信
> 今は補助メソッドを用意する方法で検討しているのですが、Accessでは何を基準に一意制約違反と判断させればいいのか・・・

JET のキー重複エラーは、コード 3022 です。
"DAO" でも "Microsoft.ACE.OLEDB.12.0" でも "Microsoft.JET.OLEDB.4.0" でも。

OleDbException から、.Errors(n).SQLState にて得られると思います。
引用返信 編集キー/
■23637 / inTopicNo.11)  Re[3]: オプティミスティック同時実行制御 Insert処理
□投稿者/ なちゃ (161回)-(2008/08/19(Tue) 20:06:13)
一意制約エラーかどうかを調べる機能をインターフェイスにして切り出すかして、
設定でチェックロジックを変更できるようにしとくのが無難かな。
現状あり得るプロバイダに関してはデフォルトでチェックできるようにしておいて、
追加が必要になった時点でチェックロジックを追加すればいいでしょう。

引用返信 編集キー/
■23643 / inTopicNo.12)  Re[4]: オプティミスティック同時実行制御 Insert処理
□投稿者/ yan (15回)-(2008/08/19(Tue) 21:18:58)
魔界の仮面弁士さん、
SQLServer、Access、Oracleのエラー番号から一意制約違反を判定することができました。
丁寧に教えていただき、ありがとうございました。

なちゃさん
インターフェースに切り出すかどうかは、これから検討してみます。

とりあえず一意制約違反が判定できましたので、解決済みとさせていただきます。
ありがとうございました。


解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -