Misunderstanding about nested TransactionScope
-
Thursday, May 03, 2007 7:55 PM
I'm exploring the TransactionScope and don't quite understand what's going on.
The following code run's fine for the two first TransactionScope,
the third one throws an exception in the DoWithoutScope function saying that the operation is not valid for the transaction state ??
Anyone knows why?
Thanks
Mateo
Code Snippetnamespace
ConsoleClient{
class Program{
static void Main(string[] args){
using (Tracer t = new Tracer("Test")){
Foo foo = new Foo();foo.Name =
"000"; using (TransactionScope scope = new TransactionScope()){
foo.DoWithoutScope();
}
foo.Name =
"001"; using (TransactionScope scope = new TransactionScope()){
foo.DoRequired(
true);foo.DoRequiresNew(
true);foo.DoSuppress(
true);foo.DoWithoutScope();
scope.Complete();
}
foo.Name =
"002"; using (TransactionScope scope = new TransactionScope()){
foo.DoRequired(
false);foo.DoRequiresNew(
false);foo.DoSuppress(
false);//THIS WILL THROW AN EXCEPTION
foo.DoWithoutScope();
}
}
}
}
public class Foo
{
private Database _db; private String _name; public Foo(){
_db =
DatabaseFactory.CreateDatabase("TestDB");}
public string Name{
get { return _name; } set { _name = value; }}
public void DoRequired(bool Complete)
{
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
{
try
{
DbCommand cmd = _db.GetStoredProcCommand("AddClient");_db.AddInParameter(cmd,
"Nom", System.Data.DbType.String, _name + " (Required)");_db.AddInParameter(cmd,
"Prenom", System.Data.DbType.String, "Mr.");_db.ExecuteDataSet(cmd);
if(Complete)scope.Complete();
}
catch (Exception exc){
Console.WriteLine(string.Format("DoRequired: {0}", exc.ToString()));}
}
}
public void DoRequiresNew(bool Complete){
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew)){
try{
DbCommand cmd = _db.GetStoredProcCommand("AddClient");_db.AddInParameter(cmd,
"Nom", System.Data.DbType.String, _name + " (RequiresNew)");_db.AddInParameter(cmd,
"Prenom", System.Data.DbType.String, "Mr.");_db.ExecuteDataSet(cmd);
if(Complete)scope.Complete();
}
catch (Exception exc){
Console.WriteLine(string.Format("DoRequiresNew: {0}", exc.ToString()));}
}
}
public void DoSuppress(bool Complete){
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Suppress)){
try{
DbCommand cmd = _db.GetStoredProcCommand("AddClient");_db.AddInParameter(cmd,
"Nom", System.Data.DbType.String, _name + " (Suppress)");_db.AddInParameter(cmd,
"Prenom", System.Data.DbType.String, "Mr.");_db.ExecuteDataSet(cmd);
if (Complete)scope.Complete();
}
catch (Exception exc){
Console.WriteLine(string.Format("DoSuppress: {0}", exc.ToString()));}
}
}
public void DoWithoutScope(){
try{
DbCommand cmd = _db.GetStoredProcCommand("AddClient");_db.AddInParameter(cmd,
"Nom", System.Data.DbType.String, _name + " (WithoutScope)");_db.AddInParameter(cmd,
"Prenom", System.Data.DbType.String, "Mr.");_db.ExecuteDataSet(cmd);
}
catch (Exception exc){
Console.WriteLine(string.Format("DoWithoutScope: {0}", exc.ToString()));}
}
}
}
All Replies
-
Thursday, May 03, 2007 9:51 PMModerator
Sure thing:
Let's take the first example, I've added comments that describes what's happening a bit:
Code Snippetfoo.Name = "001";
using (TransactionScope scope = new TransactionScope()) // A new transaction (tx1) is created
{
foo.DoRequired(true); // tx1 is used (no new transaction is created) and this inner scope completes. tx1 is still active and valid
foo.DoRequiresNew(true); // A new transaction (tx2) is created because of RequiresNew. The scope is completed and tx2 commits and goes away
foo.DoSuppress(true); // tx1 is suppressed so Completing/Not-Completing this scope does not affect tx1
foo.DoWithoutScope(); // tx1 is still active and valid so DoWithoutScope uses tx1 again -- SQL automatically picks up the ambient tx1
scope.Complete(); // All is well
}
The second example:
Code Snippetfoo.Name = "002";
using (TransactionScope scope = new TransactionScope()) // A new transaction (tx1) is created
{
foo.DoRequired(false); // tx1 is used. However because you did not complete the scope, tx1 is marked for Rollback. No new work is allowed
foo.DoRequiresNew(false); // A new transaction (tx2) is created because of RequiresNew. The scope is not-completed so tx2 rolls back
foo.DoSuppress(false); // tx1 is suppressed so Completing/Not-Completing this scope does not affect tx1
//THIS WILL THROW AN EXCEPTION
foo.DoWithoutScope(); // tx1 is not allowed to be used anymore. However, DoWithoutScope uses SQL and SQL will automatically try to use tx1
}
-
Friday, May 04, 2007 2:13 AMSure thing now!
"No new work is allowed"
i was missing this part. quite simply said but way more clear than the sdk.
Thanks a lot for your help -
Wednesday, May 09, 2007 2:59 PM
It is very clear explaination. Thank you.
But I still have one queston in first example.
foo.DoWithoutScope() uses tx1,
Is that means if any error occurred in foo.DoWithoutScope(), will foo.DoRequired() rollback?
Thank you.
-
Tuesday, May 22, 2012 9:18 PM
I am working on a similar issue..I need a tx2 withing tx1 and tx2 should rollback on certain conditions.But none of the cases work for me .I tried tx1 -New and tx2-New but resulted in an error.
Do you have a solution for this

