Signum Framework Logo
"Open framework that encourages convention over configuration, using C# code,
not XML files, to model at the right level of abstraction and achieve deadlines.
...but also has a full Linq provider, and syncs the schema for you!"



Source code




Transaction class is the most common class using Scope pattern to handle transactions in a clean and easy nestable way.

It uses the same strategy as Microsoft's TransactionScope from the client code point of view: Implicit transaction in the transaction scope defined by the using statement.

Internally, however, it has some differences, let's take a look:

How to use it

Some time ago this code tended to be very cumbersome. Implicit transactions, however, made a big step forward, creating a easy model to handle transactions writing less code:

private static void FixBugs()
  var wrongBugs = from b in Database.Query<BugDN>()
                  where b.Status == Status.Fixed && !b.End.HasValue
                  select b.ToLazy();

foreach (var lazyBug in wrongBugs) { BugDN bug = lazyBug.Retrieve(); bug.Description += "- Fix it!"; bug.Save(); } }

This simple code contains a lot of intensive work with the database: the query, retrieving each Bug, and saving it. Currently all of these are independent operations, so we could have some problems:

  • If some exception is thrown in the middle of the process we end up having some bugs fixed and some remaing. This could have some problems, like duplicating - Fix It! for some bugs once you r-run the process.
  • It could take some time from the time the query gets executed, to the moment the BugDN is actually retrieved (we are using lazy objects). Someone could have modified the Bug in the meantime.

In Signum Engine, every atomic operation, like retrieving an object, executing a query, or saving an object graph is transactional without you having to do anything.

Sometimes, however, you want to glue together operations in the same transaction, so you have a consistent view of the database (not influenced by concurrency) and you don't commit partial modifications if something goes wrong in the middle.

This is as easy as surrounding the code with a suing Transaction block, like this:

private static void FixBugs()
    using (Transaction tr = new Transaction())
        var wrongBugs = from b in Database.Query<BugDN>()
                        where b.Status == Status.Fixed && !b.End.HasValue
                        select b.ToLazy();

foreach (var lazyBug in wrongBugs) { BugDN bug = lazyBug.Retrieve(); bug.End = bug.Start.AddDays(7); bug.Save(); }

tr.Commit(); } }

What we do is to create a transaction, do our work, and at the end Commit it. When the transaction is disposed, if it hasn't been committed, it gets roll backed automatically, so the code gets much more simple to read.

Be careful with return statements, remember to commit the transaction before exit the method!

The nice thing is that all the old code doesn't need to be updated with the new declared Transaction tr, because transactions are handled implicitly.

Also, if you call FixBigs from a method like this:

private static void FixTheWorld()


FixDevelopers(); }

You cold also glue together all the inner transactions creating a new, wider one:

private static void FixTheWorld()
    using (Transaction tr = new Transaction())



tr.Commit(); } }

The end result is that the inner transactions become silent without you having to change anything, so the code is much more easy to combine.

There are some options for useful overloadings of Transaction constructor:

//Creates a nestable transaction
public Transaction()

//If forceNew == true, the new transaction is independent from the parent public Transaction(bool forceNew) //Allows to change the IsolationLevel of the transaction (only if ends up being the parent trnasaction) public Transaction(IsolationLevel isolationLevel)

//The two above combined public Transaction(bool forceNew, IsolationLevel? isolationLevel)

How it works (AdvancedTopic)

There are some things that are important to know in advanced scenarios:

  • Each time you force a new transaction, a RealTransaction is pushed into the transaction stack. There are different stacks per Thread and Connection.

  • Transaction knows the start time of the transaction, that is used to update the Entity Ticks column for concurrency control.

  • Transactions are completely silent on MockConnections

  • Transaction takes control of SqlClient SqlTransaction and SqlConnection. You can access them on Transaction.CurrentConnection and Transaction.CurrentTransaccion (they will be created if not created yet).

Probably you where expecting Connection to handle SqlConnection, but Connection is more like a potential connection than an actual one, and it's shared between threads. Transaction has better knowledge about when to start the connection and how long to keep it open.

Creative Commons License Signum Framework Site by Signum Software is licensed under a Creative Commons Attribution 3.0 License.
Powered by ScrewTurn Wiki version