Search code examples
c#sql-servertransactionscope

C# transaction with handled exception will still roll back?


Considering this piece of code:

using(TransactionScope tran = new TransactionScope()) {

    insertStatementMethod1();
    insertStatementMethod2();
    // this might fail
    try {
        insertStatementMethod3();
    } catch (Exception e) {
        // nothing to do
    }

    tran.Complete();
}

Is anything done in insertStatementMethod1 and insertStatementMethod2 going to be rolled back? In any case? If I want them to execute anyway, I would need to check if it insertStatementMethod3 will fail before the transaction, and build my transaction code based on that?

Update

The code looks similar to this

using(TransactionScope tran = new TransactionScope()) {
    // <standard code>
    yourExtraCode();
    // <standard code>
    tran.Complete();
}

where I get to write the yourExtraCode() method

public void yourExtraCode() {
    insertStatementMethod1();
    insertStatementMethod2();

    // this call might fail
    insertStatementMethod3();
}

I can only edit the yourExtraCode() method, so I cannot chose to be in the transaction scope or no. One simple possible solution would be this:

public void yourExtraCode() {
    insertStatementMethod1();
    insertStatementMethod2();

    // this call might fail
    if (findOutIfIcanInsert()) { // <-- this would come by executing sql query
        try {
            insertStatementMethod3();
        } catch (Exception e) {
            // nothing to do
        }
    }
}

But that would come with the need of looking up things in the db which would affect performance. Is there a better way, or I need to find out before I'd call the method? I tried out and, of course the transaction was rolled back as expected.


Solution

  • If you don't want your first two methods to be transacted, just move them out from the ambient transaction's scope.

    If you don't have control over the code which starts an ambient transaction, you can suppress it by creating a new ambient transaction: using (var scope = new TransactionScope(TransactionScopeOption.Suppress)).