I am trying to make a quick dummy application so that I can learn all aspects of System.Transactions. This application interacts with two different SQLExpress DB. If I pull out the transaction statistics in the component services, I can see the transaction starting in the external Scope when the second connection opens. If failOuter is true, the transaction is aborted, but it does not throw any exceptions. When failInner is true, a TransactionAbortedException is thrown.
From MSDN:
When your application completes all the work that it wants to perform in a transaction, you must call the Complete method only once to tell the transaction manager that it is acceptable to complete the transaction. It is very good practice to call Complete as the last statement in the use block.
Failure to follow this method aborts the transaction because the transaction manager interprets this as a system failure or is equivalent to an exception that is part of the transaction volume.
A TransactionAbortedException is thrown if the scope creates a transaction and the transaction is aborted.
Based on this, I would expect my outerScope to throw a TransactionAbortedException, since my transaction statistics show a choppy transaction every time I launch my application with the failOuter parameter equal to true. My method returns true, since no exceptions are thrown, even if the transaction is aborted. If I do not cancel the internal transaction, then it behaves as I expected. Any clarification would be most appreciated.
public bool CreateNestedTransaction(bool failOuter, bool failInner)
{
try
{
using (TransactionScope outerScope = new TransactionScope())
{
using (SqlConnection myConnection = new SqlConnection("server=(local)\\SQLExpress;Integrated Security=SSPI;database=test1"))
{
SqlCommand myCommand = new SqlCommand();
myConnection.Open();
myCommand.Connection = myConnection;
myCommand.CommandText = "update test set Value = ((select Value from test where Id = (select max(Id) from test))+1) where Id = (select max(Id) from test)";
myCommand.ExecuteNonQuery();
}
using (SqlConnection myConnection = new SqlConnection("server=(local)\\SQLExpress;Integrated Security=SSPI;database=test1"))
{
SqlCommand myCommand = new SqlCommand();
myConnection.Open();
myCommand.Connection = myConnection;
myCommand.CommandText = "update test set Value = Value";
myCommand.ExecuteNonQuery();
}
using (TransactionScope innerScope = new TransactionScope())
{
using (SqlConnection myConnection = new SqlConnection("server=(local)\\SQLExpress;Integrated Security=SSPI;database=test2"))
{
SqlCommand myCommand = new SqlCommand();
myConnection.Open();
myCommand.Connection = myConnection;
myCommand.CommandText = "update test set Value = ((select Value from test where Id = (select max(Id) from test))+1) where Id = (select max(Id) from test)";
myCommand.ExecuteNonQuery();
}
if (failInner == false) { innerScope.Complete(); }
}
if (failOuter == false) { outerScope.Complete(); }
}
}
catch (TransactionAbortedException)
{
return false;
}
return true;
}
source
share