2013-07-09 26 views
5

Wir haben versucht, den Datenbankstatus aus diagnostischen Gründen zu überprüfen. Daher haben wir unsere Modifikations-ORM-Abfragen in einem TransactionScope zusammen mit einer zweiten Abfrage mit Diagnosefunktionen verpackt. so etwas wie dieses: tun ihr Bit in einem verschachtelten TransaktionsbereichTransactionScope Wrapping von ORM-Aufrufen, TransactionStateAborted.CreateAbortingClone-Ausnahme beim zweiten Aufruf

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

Es ist eine handgerollte ORM, und beide diese Anrufe am Ende nach unten am Boden. Mit anderen Worten, wenn Sie graben, DeleteItem() hat mit (Transaction newScope = new Transaction (TransactionScopeOptions.Required, _maxTimeout) {...}

und CheckIntegrity() auch das gleiche hat.

In den meisten Fällen hat es funktioniert, aber ich bin über eine seltsame Bedingung gelaufen.Wenn jemand einige schlechte Eingaben in die Abfrage eingibt, kann der DeleteItem() Aufruf eine Ausnahme auslösen.Diese Ausnahme wird komplett gefangen und behandelt bei a Stacklevel unter dem Wrapper Ich glaube, dass auch Exception vor geworfen wird, um das TransactionScope zu verschachteln

Wenn wir jedoch beim CheckItegrity() - Aufruf zur Erstellung des verschachtelten Bereichs gelangen, wird vom CreateAbortingClone-Konstruktor ein Fehler "Transaktion wurde abgebrochen" ausgegeben. Die innere Ausnahme ist null.

Die meisten anderen Erwähnung der CreateAbortingClone-Interaktion hat mit DTC-Promotion (oder Fehler davon) zu tun und die innere Ausnahme spiegelt das wider.

Ich folge daraus, dass die Abbruch-Ausnahme beim Aufruf von CheckIntegrity() darauf zurückzuführen ist, dass DeleteItem() eine Ausnahme ausgelöst hat - obwohl sie verschluckt wurde.

A) ist das eine korrekte Schlussfolgerung? Ist ein TransactionScope anfällig für Ausnahmen, die ausgelöst oder bearbeitet werden?

B) Gibt es eine Möglichkeit, dies vor dem CheckIntegrity() - Aufruf zu erkennen? Ich meine anderes als unsere ORM wieder zu tun, um die Ausnahme percole oder eine andere globale Flagge hinzuzufügen?

Dank Mark

+0

Stochern ein bisschen mehr im Debugger, finde ich, dass TransactionScope.expectedCurrent .InternalTransaction.State ist TransactionStateAborted nach dem DeleteItem() - Aufruf, der meine Inferenz unterstützt. Problem ist, dass alle Mitglieder privat sind ... – user1664043

+0

msdn docs gefunden "Wenn eine Ausnahme innerhalb des TransactionScope auftritt, wird die Transaktion als inkonsistent markiert und abgebrochen." Zwischen den Zeilen bleibt jedoch eine Menge ungesagt. So scheint es keinen Unterschied zu machen, ob die Ausnahme einige Aufrufebenen unterhalb des Bereichs behandelt, und verhindert, dass neue Bereiche anschließend verschachtelt werden. – user1664043

+1

Hinweis in einer Flasche Zeit - schließlich fand ich System.Transactions.Transaction.Current.TransactionInformation.Status und dachte, es kann verwendet werden, um festzustellen, ob irgendwelche Ausnahmen (behandelt oder nicht behandelt) Ihre Wrapping-Transaktion verdorben haben. Wenn es sich um TransactionStatus.Aborted handelt, bist du abgespritzt. Es ist mir auch aufgefallen, dass Sie eine Wrapping-Transaktion auf einer äußeren Ebene verwenden können, um festzustellen, wann eine Ausnahme ausgelöst wurde. Bei Ihrem äußersten äußeren Aufruf müssen Sie keine aufeinanderfolgenden db-Aufrufe in verschiedenen Layern erwarten. Natürlich wäre es besser, Ihren Code so zu gestalten, dass er wichtige Ereignisse nicht verschluckt. – user1664043

Antwort

0

ich nur wissen, wie das mit EF (Entity Framework) arbeitet

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

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


    } 
} 

Dann wird die Transaktion auf den Kontext verknüpft ist. Ich bin nicht formell darüber, wie Ihr Code diese Verbindung herstellt, aber es kann sich um etwas ausgefallenes Build-Zeug handeln.

Dann ist es am besten, dies zu wickeln in einem 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); 
} 

so endgültiger Code wie

aussehen würde
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); 
     } 

    } 
} 
Verwandte Themen