2013-07-09 77 views
5

我們試圖做一些完整性檢查我們的數據庫狀態用於診斷的原因,所以我們包裹我們加上跑診斷第二查詢一個TransactionScope修改ORM查詢 - 是這樣的:的TransactionScope包裝ORM電話,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」事務。內部異常爲空。

大多數CreateAbortingClone互動的每一個其他提及與DTC促銷(或失敗物)和內部異常做反映。

我推斷CheckIntegrity()調用中的異常異常是由於DeleteItem()引發了異常 - 即使它被吞下了。

A)是一個正確的推理? TransactionScope是否對所有拋出,處理或不處理的異常敏感?

B)有沒有什麼辦法來檢測使CheckIntegrity()調用之前?我的意思是重新做我們的ORM讓異常滲透或添加其他全局標誌?

感謝 馬克

+0

周圍多一點在調試器戳,我發現TransactionScope.expectedCurrent .InternalTransaction.State是DeleteItem()調用後的TransactionStateAborted,支持我的推理。問題是所有這些成員是私人的... – user1664043

+0

發現msdn文檔說:「如果在TransactionScope內發生異常,事務被標記爲不一致並被放棄。」但是在這兩行之間還有很多沒有用到的地方 - 比如,如果異常處理的是低於範圍的幾個調用級別,那麼它就不會出現問題,並且它可以防止任何新的範圍在之後被嵌套。 – user1664043

+1

注意瓶子裏的時間 - 最終我發現了System.Transactions.Transaction.Current.TransactionInformation.Status,並認爲它可以用來判斷是否有任何異常(已處理或未處理)破壞了包裝事務。如果它是TransactionStatus.Aborted,那麼你已經洗腦了。我還想到,您可以在外層使用包裝事務來檢測何時拋出異常。在你外面的呼叫中,你並不希望連續的數據庫調用進入不同的層。當然,設計你的代碼不要吞噬重大事件會更好。 – user1664043

回答

0

我只知道這是如何工作與EF(實體框架)

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

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


    } 
} 

那麼交易鏈接到上下文。我不是關於你的代碼如何實現這種連接的類比,但可能是一些奇特的構建。

那麼最好是包裹在這一個try/catch

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); 
     } 

    } 
}