2013-07-09 12 views
5

Staraliśmy się wykonać pewne sprawdzenia integralności w naszym stanie bazy danych z powodów diagnostycznych, więc opakowaliśmy nasze zapytania modyfikacji ORM w TransactionScope w połączeniu z drugim zapytaniem, które przeprowadziło diagnostykę - coś takiego:TransactionScope zawijanie wywołań ORM, wyjątek TransactionStateAborted.CreateAbortingClone przy drugim wywołaniu

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

jest to ręcznie zwijane ORM, a obie te rozmowy kończy się robi ich trochę w zagnieżdżonych zakresie transakcji na dole. Innymi słowy, kiedy wykopać dół, DeleteItem() ma using (TransactionScope newScope = new TransactionScope (TransactionScopeOptions.Required, _maxTimeout) {...}

i CheckIntegrity() ma również takie same.

W większości przypadków działało poprawnie, ale wystąpił dziwny stan.Jeśli ktoś wkłada jakieś błędne dane wejściowe do kwerendy, wywołanie DeleteItem() może rzucić wyjątek.Ten wyjątek jest całkowicie złapany i obsługiwane w poziom stosu poniżej opakowania.Myślę, że wyjątek jest również wyrzucany przed dostaje się do zagnieżdżenia TransactionScope.

Ale kiedy wchodzimy do tworzenia zagnieżdżonego zakresu w wywołaniu CheckIntegrity(), generuje on komunikat "Transakcja została przerwana" z konstruktora CreateAbortingClone. Wewnętrzny wyjątek jest pusty.

Większość każdej wzmianki o interakcji CreateAbortingClone ma związek z promocją DTC (lub jej awarią), a wewnętrzny wyjątek odzwierciedla to.

Podejrzewam, że przerwanie wyjątku w wywołaniu CheckIntegrity() spowodowane jest faktem, że funkcja DeleteItem() rzuciła wyjątek - mimo że został połknięty.

) Czy to poprawna konkluzja? Czy transakcja jest podatna na wszelkie wyjątki odrzucane, obsługiwane lub nie?

B) Czy istnieje sposób na wykrycie tego przed wykonaniem wywołania CheckIntegrity()? Mam na myśli inne niż ponowne wykonanie ORM, aby wyjątek mógł się przenikać lub dodać inną globalną flagę?

Dzięki Mark

+0

grzebie się trochę bardziej w debugger, uważam, że TransactionScope.expectedCurrent .InternalTransaction.State jest TransactionStateAborted po wywołaniu DeleteItem(), podnosząc moje wnioskowanie. Problem polega na tym, że wszyscy członkowie są prywatni ... – user1664043

+0

Znaleziono dokumentację msdn mówiącą: "Jeśli wyjątek wystąpi w TransactionScope, transakcja jest oznaczona jako niespójna i jest porzucana." ale między wierszami jest dużo niedopowiedzi - jakby nie wydawało się ważne, czy wyjątek obsługuje kilka poziomów połączeń pod zakresem, i zapobiega zagnieżdżaniu się nowych zasięgów. – user1664043

+1

Uwaga w butelce - w końcu znalazłem System.Transactions.Transaction.Current.TransactionInformation.Status i uznałem, że można go użyć do stwierdzenia, czy jakiekolwiek wyjątki (obsługiwane lub nieobsługiwane) zepsuły transakcję pakowania. Jeśli to TransactionStatus. Przyszło mi również do wniosku, że można użyć transakcji zawijania na poziomie zewnętrznym, aby wykryć, kiedy wyjątek został zgłoszony. Przy twoim dalekim zewnętrznym wywołaniu nie możesz oczekiwać kolejnych wywołań db na różne warstwy. Oczywiście lepiej byłoby zaprojektować swój kod, aby nie połknąć istotnych wydarzeń. – user1664043

Odpowiedz

0

wiem tylko jak to działa z Entity Framework (EF)

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

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


    } 
} 

wówczas transakcja jest związana z kontekstem. Nie jestem formilarny na temat tego, jak twój kod tworzy to połączenie, ale może to być trochę fajna kompilacja.

Wtedy najlepiej jest owinąć to w 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); 
} 

więc ostateczny kod wyglądałby

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

    } 
} 
Powiązane problemy