3

これはかなり奇妙な状況に陥りました。私の状況にはいくつかの層があります。私はすべての層が厳密に必要とされているかどうかを識別しますが、ここで何が起こっているのかいなかった。SqlDataAdapterおよびアンビエントトランザクションで失われたテーブルをロックするトリガーのSQL Serverエラー

  • C#のコードがSqlConnectionが自動的に入隊しているにアンビエントトランザクションを作成しています。
  • C#コードでは、SqlDataAdapterを使用してテーブルに行を挿入しています。
  • InsertCommandはストアドプロシージャを参照しています。ストアドプロシージャは、簡単なINSERTステートメントです。
  • INSERTが実行されているテーブルには、トリガーがありますINSTEAD OF INSERT
  • トリガーは、テーブルに対して排他ロックを取得します。
  • トリガー内でエラーが発生しました。

この組み合わせでは、C#コード内でエラーは発生しません。ただし、トリガーがでない場合、はテーブルに排他ロックを取得しますが、エラーはC#コードまで行います。

エラーは実際にはですが、SQL Server側ではトランザクションが中断されていることがわかります。 C#コードは、トランザクションが中止されたことを知らず、TransactionScopeの処分がCOMMIT TRANSACTIONになるとエラーに遭遇するだけです。

私は、このシナリオの最小限の再現作成しました:誰もが、これはあるかもしれない、とどのように適切なエラーの挙動を扱うが復元されるかもしれない理由のいずれかの理解を持っています

https://github.com/logiclrd/TestErrorWhileLockedInTrigger

を?

+0

これを見て、「Database Initialization.sql」とコードの不一致によって混乱した人は、それは私の悪いことです。 gitを追加してコミットする前に 'Save'を押すのを忘れました。私は正しい初期化コードでフォローアップコミットを行った。 –

答えて

0

私は問題の原因を特定しました。

テーブルをロックトリガー内のステートメントが、このように見えた:

SELECT TOP 0 * 
    FROM TableToTriggerAndLock WITH (TABLOCKX, HOLDLOCK) 

これはデータを返さないが、リターン(空)を行い結果セット。 SqlDataAdapterクラスはTDSストリームに戻ってくる最初の結果セットだけを気にするので、の2番目の結果セットに戻るエラーは完全に渡されます。

ロックステートメントを取り出すと、その冗長な結果セットが取り出され、エラーはの最初の結果セットにあります。これはそこに誰かSqlDataAdapter、より複雑な基礎となる操作で作業するのに役立ちます

DECLARE @Dummy INT 

SELECT TOP 0 @Dummy = 1 
    FROM TableToTriggerAndLock WITH (TABLOCKX, HOLDLOCK) 

希望を:

ソリューションは、それから、私のように、ロックステートメントを再加工することにより行った結果セットを、抑制することです。 :-)

1

私はこれについてさらにテストを行った。

私の最初の考えは、排他的なロックを保持しているとエラーをスケルチさせていた場合、明示的にロックを解除すると、だから私はROLLBACK TRANSACTIONとそれに加えてTHROWを持っていたが、それは何もしなかった。

次に、私の次の考えは、重度レベル20-25で使用された場合、強制的に接続を終了します。これが理想的な解決策であるかどうかはわかりません。なぜなら、これが起きるとSQL Serverイベントログにもエントリが書き込まれるからです。ただし、になります。SqlDataAdapterは、Updateコマンド中に、トランザクションがまだアクティブであり、コミットしようとしているC#コードではなく、エラーを参照してください。

この「スレッジハンマー」アプローチの他の潜在的な短所を知っている人はいますか、あるいはこの状況で正しくエラーが伝播する唯一の方法になる可能性はありますか?

関連する問題