2013-07-09 23 views
5

診断状態でデータベース状態の整合性チェックを実行しようとしていましたので、Diagnosticsを実行した2番目のクエリこのような何か:TransactionScopeはORM呼び出しをラップします.2番目の呼び出しでTransactionStateAborted.CreateAbortingClone例外が発生しました。

using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, _maxTimeout)) 
{ 
    ORM.DeleteItem(); 
    ORM.CheckIntegrity(); 
    scope.Complete(); 
} 

それは手巻きORMだし、両方のこれらの呼び出しは、下部にダウンネストされたトランザクションスコープで自分のビットをやってしまいます。言い換えれば、ときに掘り下げる、DeleteItemは、()(のTransactionScope newScope =新しいのTransactionScope(TransactionScopeOptions.Required、_maxTimeout) {...}

とCheckIntegrityは()も同じ有し用い を有している。

ほとんどの場合、うまくいきましたが、奇妙な状況に遭遇しました。誰かがクエリに不正な入力を加えた場合、DeleteItem()コールは例外をスローする可能性があります。スタックレベルをラッパーの下に置いてください。の前に例外がスローされ、の前にTransactionScopeがネストされると考えられます。

しかし、CheckIntegrity()呼び出しでネストされたスコープの作成に至ると、CreateAbortingCloneコンストラクターから "Transaction was aborted error"がスローされます。内部例外はnullです。

CreateAbortingCloneのやりとりのほとんどの他の言及は、DTCのプロモーション(またはその失敗)と関係があり、内部の例外はそれを反映しています。

私は、CheckIntegrity()呼び出しの中断例外は、DeleteItem()が例外をスローしたという事実が原因であると推測しています。

A)は正しい推論ですか? TransactionScopeは、投げられた、処理された、または処理されなかった例外に敏感ですか?

B)CheckIntegrity()呼び出しを行う前にそれを検出する方法はありますか?私は例外が他のグローバルフラグを追加または追加するようにORMを再実行する以外のことを意味しますか?

おかげ マーク

+0

次のようになりますのtry/catchでこれをラップするのが最善ですが、私はそれを見つけるTransactionScope.expectedCurrent .InternalTransaction.StateはDeleteItem()呼び出しの後にTransactionStateAbortedされ、私の推論を強化します。問題はこれらすべてのメンバーがプライベートであることです... – user1664043

+0

msdn docsが "TransactionScope内で例外が発生した場合、トランザクションは一貫性がないとマークされ、中止されました。例外がスコープの下にいくつかのコールレベルで処理されても問題にならないように見え、その後に新しいスコープがネストされるのを防ぐことができます。 – user1664043

+1

ボトルの時間に注意してください - 最終的に私はSystem.Transactions.Transaction.Current.TransactionInformation.Statusを発見し、例外(処理済みまたは未処理)がラッピングトランザクションを損なったかどうかを知るために使用できると考えました。それがTransactionStatus.Abortedの場合、あなたは縛られています。また、例外がスローされたときを検出するために、外部レベルでラップトランザクションを使用することもできます。あなたの外側の呼び出しでは、連続したdb呼び出しを別のレイヤーに期待する必要はありません。もちろん、重要な出来事を飲み込まないようにコードを設計する方が良いでしょう。 – user1664043

答えて

0

私は、これはEFでどのように機能するかだけを知っている(エンティティフレームワーク)

using (var context = new MyContext(this._connectionString)) 
{ 

    using (var dbContextTransaction = context.Database.BeginTransaction()) 
    { 


    } 
} 

その後の取引は、コンテキストにリンクされています。私はあなたのコードがその接続をどのようにしているかについては定かではありませんが、何か面白いものを構築するかもしれません。

そして、それは

try 
{ 
    // do-stuff 
    context.SaveChanges(); 
    //NB!!!!!! 
    //---------------------- 
    dbContextTransaction.Commit(); 
} 
catch (Exception ex) 
{ 
    dbContextTransaction.Rollback(); 
    //log why it was rolled back 
    Logger.Error("Error during transaction,transaction rollback", ex); 
} 

ので、最終的なコードは、より多くのデバッガで少しチャンスをうかがっ

using (var context = new MyContext(this._connectionString)) 
{ 

    using (var dbContextTransaction = context.Database.BeginTransaction()) 
    { 
     try 
     { 
       // do-stuff // 
       context.SaveChanges(); 
       /////////////////////// 
       //if any exception happen, changes wont be saved unless Commit is called 
       //NB!!!!!! 
       //---------------------- 
       dbContextTransaction.Commit(); 
     } 
     catch (Exception ex) 
     { 
       dbContextTransaction.Rollback(); 
       //log why it was rolled back 
       Logger.Error("Error during transaction,transaction rollback", ex); 
     } 

    } 
} 
関連する問題