Simpler Transactions

The .NET Framework provides support for managing transactions from code via the System.Transactions infrastructure. Performing database operations in a transaction is as easy as writing a using block with the TransactionScope class.

using(TransactionScope transaction = new TransactionScope()) 
{
  DoSomeWork();
  SaveWorkToDatabase();

  transaction.Complete();
}

At the end of the using block, Dispose is called on the transaction scope. If the transaction has not been completed (in other words, transaction.Complete was not called), then the transaction is rolled back. Otherwise it is committed to the underlying data store.

The typical reason a transaction might not be completed is that an exception is thrown within the using block and thus the Complete method is not called.

This pattern is simple, but I was looking at it the other day with a co-worker wondering if we could make it even simpler. After all, if the only reason a transaction fails is because an exception is thrown, why must the developer remember to complete the transaction? Can’t we do that for them?

My idea was to write a method that accepts an Action which contains the code you wish to run within the transaction. I’m not sure if people would consider this simpler, so you tell me. Here’s the usage pattern.

public void SomeMethod()
{
  Transaction.Do(() => {
    DoSomeWork();
    SaveWorkToDatabase();
  });
}

Yay! I saved one whole line of code! :P

Kidding aside, we don’t save much in code reduction, but I think it makes the concept slightly simpler. I figured someone has already done this as it’s really not rocket science, but I didn’t see anything after a quick search. Here’s the code.

public static class Transaction 
{
  public static void Do(Action action) 
  {
    using (TransactionScope transaction = new TransactionScope())
   {
      action();
      transaction.Complete();
    }
  }
}

So you tell me, does this seem useful at all?

By the way, there are several overloads to the TransactionScope constructor. I would imagine that if you used this pattern in a real application, you’d want to provide corresponding overloads to the Transaction.Do method.

UPDATE: What if you don’t want to rely on an exception to determine whether the transaction is successful?

In general, I tend to think of a failed transaction as an exceptional situation. I generally assume transactions will succeed and when they don’t it’s an exceptional situation. In other words, I’m usually fine with an exception being the trigger that a transaction fails.

However, Omer Van Kloeten pointed out on Twitter that this can be a performance problem in cases where transaction failures are common and that returning true or false might make more sense.

It’s trivial to provide an overload that takes in a Func<bool>. When you use this overload, you simply return true if the transaction succeeds or false if it doesn’t, which is kind of nice. Here’s an example of usage.

Transaction.Do(() => {

  DoSomeWork();
  if(SaveWorkToDatabaseSuccessful()) {
    return true;
  }
  return false;
});

The implementation is pretty similar to what we have above.

public static void Do(Func<bool> action) {
  using (TransactionScope transaction = new TransactionScope()) {
    if (action()) {
      transaction.Complete();
    }
  }
}

What others have said

Requesting Gravatar... Scott Aug 19, 2009 2:24 AM
# re: Simpler Transactions
That's a nice idea and one that is used in good JavaScript code all the time.
Requesting Gravatar... Peter Lanoie Aug 19, 2009 2:26 AM
# re: Simpler Transactions
This seems like a logical implementation of a transaction. After all, if you are explicitly using a transaction isn't the general intent to commit it?

How will this behave if I do an explicitly rollback from within the transaction's Action? Transaction.Complete() must respect a previous rollback() I imagine. (Haven't worked with txs much.) So after an explicit Rollback() the implicit Complete() really has nothing to do so it can still execute.
Requesting Gravatar... Ian Suttle Aug 19, 2009 2:26 AM
# re: Simpler Transactions
Funny you bring this up. I was working with TransactionScope the other day and had forgotten to Complete() it. You'd have save'd me some headaches there :).

While I like the creative aspect of shortcutting the process I find the original implementation easier to read and therefore easier to maintain.
Requesting Gravatar... Steve Smith Aug 19, 2009 2:39 AM
# re: Simpler Transactions
I like it. I don't use transactions all that often, but this seems to me to be the same kind of simplification that saves bugs as when we moved from ADO to ADO.NET and replaced

while Not RS.EOF
...
RS.MoveNext 'Do not forget this line!
end while

to:
while(myDataReader.Read()
{
...
}

Eliminating the need for the last (required) call in the pattern is definitely a good thing.
Requesting Gravatar... Eduardo Campañó Aug 19, 2009 2:53 AM
# re: Simpler Transactions
Nice, less code, i like that
Requesting Gravatar... Colin Whitlatch Aug 19, 2009 3:12 AM
# re: Simpler Transactions
I use the same technique ( passing actions around ) forgeneric exception handling ( just logging! ) & launching simple threads. I hadn't thought about doing it with transactions, I like it!
Requesting Gravatar... Paco Aug 19, 2009 3:56 AM
# re: Simpler Transactions
Personally, I would not use it. I wrap the transaction in a unit of work. For 99% of the cases, I start a transaction on the begin of a webrequest, and commit it at the end.

With the implementation you use, you have to manage the transaction all over the application, everywhere where data-access is used. In a typical application, just one (or two or three) places are enough.
Requesting Gravatar... Michael Monteleone Aug 19, 2009 4:02 AM
# re: Simpler Transactions
I have been using this technique for years, though never blogged about it. When anonymous delegates (and later lambdas) were released, database transactions seemed a textbook use-case.

Another great use is memoization, backed by what-have-you. (Cache, Session, HttpContext items)

SomeType someMemoizedItem = LazyCache.Fetch<SomeType>("cacheKey", ()=> {
// perform expensive action here
return new SomeType();
});

Wherein Fetch() does the lifting of checking if the item is cached, and if not creating it and caching it.

Requesting Gravatar... David Mohundro Aug 19, 2009 4:03 AM
# re: Simpler Transactions
I saw this technique used the first time by Venkat Subramanium at www.agiledeveloper.com/.../PermaLink.aspx. His code wasn't wrapping transactions, just IDisposable. Still, a nice technique that functional programming can provide.
Requesting Gravatar... Dummy Customer Aug 19, 2009 4:07 AM
# re: Simpler Transactions
I don't like it!

I think that your new solution is less readable than the initial code.

This is an extra abstraction layer that causes the code to be less readable and also less easier to debug.

The debugging of your code becomes more difficult, because an exception will bubble in the Do() method. So Visual Studio will break in the Do() method. So the only way to actually see where the exception occurred is to go through the stack trace.

In essence, you want an exception to hit as close to the actual code that caused it. And yes, I know that can be difficult to achieve.

Also, Transactions are usually used in business apps.
All transactions usually go through a Save() method in your business app. Having multiple transactions and transaction scopes throughout a business app is usually a bad sign.

The Save() method is the uber method that does saving, transactions, logging, exception bubbling, translation of exception message etc.

Applying your solution to the Save() method will decrease that method with one line, but it will also add additional indirection and complexity where it is not needed.

So conclusion:
It's always good to think about code reduction, but it has to make sense in a real world solution and I don't see this having a real world benefit.

Requesting Gravatar... Kevin Aug 19, 2009 4:48 AM
# re: Simpler Transactions
Maybe you can send parameter to delegate to configure TransactionOptions, like IsolationLevel and Timeout, that are important configurations at Transaction level.
Requesting Gravatar... José Romaniello Aug 19, 2009 4:54 AM
# re: Simpler Transactions
We have something like this for testing purposes at unhaddins. (enclose the nh session and transaction)
Look this http://digg.com/u1B1bT.
Requesting Gravatar... Ragan Martin Aug 19, 2009 6:21 AM
# re: Simpler Transactions
Simple and understandable Code works better than saving a couple of lines in code, saving 10 lines of codes sometimes means 30 minutes of explanation for a new developer in my team.

Use code that everybody understands and you'll be more productive.
Requesting Gravatar... Michael Teper Aug 19, 2009 6:39 AM
# re: Simpler Transactions
A small nitpick, but I would have named it Transactional.Do(), which I think reflects what's going on slightly better.
Requesting Gravatar... Scott Bellware Aug 19, 2009 7:56 AM
# re: Simpler Transactions
Yep, used to do this back in the day :)

The problem with this (and all uses of the dispose pattern for anything other than it's original intention) is that you have to know the code inside the Dispose method, or in this case, the Do method.

It's inevitably a violation of encapsulation.

Implicit semantics remove lines of code from code, while simultaneous removing meaning. The one doesn't do justice to the other.

Ultimately, forgetting to write the line of code to complete a transaction isn't much of a productivity problem. It would have been readily discovered by the functional tests for the feature.

You do write your own functional tests, don't you :)
Requesting Gravatar... Tobin Harris Aug 19, 2009 8:23 AM
# re: Simpler Transactions
I always forget to commit transactions, and since I've been doing it for 14 years, I think this makes for great discussion!

The using pattern is great for enforcing safe disposal or resources, but I suspect it's orthogonal to transaction commit/rollback?

With that out of the picture, then I personally prefer to fall back on the rule of least surprise. For me, I always like code to read in such a way that it prioritises the best-case-scenario. This means that ransactions should commit by default.

In SQL Server Managment Studio this is the default setting - you execute SQL and it automatically commits. On the other hand, last time I used Oracle SQL tools, you had to explicitly commit your work.

So, for some developers, transactions should rollback by default. For other developers, transactions should complete by default. It's cultural.

The explicitness of transaction.Complete() is great when there is no standard way of doing things. And I think there is no standard way of doing things. So, I say we need to be explicit and write transaction.Complete() in our code, rather than relying in a convention.



Requesting Gravatar... Tobin Harris Aug 19, 2009 8:32 AM
# re: Simpler Transactions
Actually, I concluded badly there. I think the using block should throw an exception if the transaction is neither committed or rolled back.
Requesting Gravatar... Scott Bellware Aug 19, 2009 8:38 AM
# re: Simpler Transactions
Tobin,

Throwing an exception in a using block is something that, while not verboten to the pattern, I would consider to stretch least surprise uncomfortably.
Requesting Gravatar... Haacked Aug 19, 2009 8:42 AM
# re: Simpler Transactions
@bellware Interestingly, I think the current behavior of transaction scope is weird. When I see a using block, I naturally think of it as defining a scope. And within that scope, something is different.

For example, within a lock statement, I expect everything inside to be governed by the lock. When you leave the lock block, I expect the lock to be released.

So I find it odd that I have to call transaction.Complete() at all. I kind of think it's only there to prevent the transaction from being disposed of prematurely, not sure though.

That's how I read the Do method. Everything in there is part of the transaction.

In fact, the original intention of the Dispose pattern was to delineate and dispose of a scope, not just harmful resources. At least that's what Eric Gunnerson once told me ;).


Not only that, the TimedLock demonstrates what the C# team had in mind with the using statement. It wasn't intended just for cleanup, but for situations just like this.
Requesting Gravatar... Michael Monteleone Aug 19, 2009 8:45 AM
# re: Simpler Transactions
I understand the concerns that this hides explicitness, but I think in this case it's OK, especially as the intent is still obvious and the hidden code is boilerplate. For the record, Ruby on Rails also uses an identical approach:

ActiveRecord::Base.transaction do
david.withdrawal(100)
mary.deposit(100)
end

That being said, this discussion smells particularly bike-sheddy.
Requesting Gravatar... alberto Aug 19, 2009 8:47 AM
# re: Simpler Transactions
There is something similar in Ayende's Rhino.Commons.
You can see an example here
Requesting Gravatar... Neal Blomfield Aug 19, 2009 8:56 AM
# re: Simpler Transactions
Tobin's idea sounds much more appealing.

public static void Enforce(Action[TransactionScope] action)
{
using (TransactionScope transaction = new TransactionScope())
{
action(transaction);
var txStatus = Transaction.Current.TransactionInformation.Status;
if( txStatus == TransactionStatus.InDoubt )
{
throw new InDoubtTransactionException();
}
}
}
Requesting Gravatar... Johnvpetersen Aug 19, 2009 9:45 AM
# re: Simpler Transactions
Re: @haacked's comment about
having to invoke complete, completing a tx
should be an explicit, not an implicit act. The
using is just about what is on scope.
DB actions are a different thing altogether.

I like your approach.
Requesting Gravatar... zvolkov Aug 19, 2009 9:52 AM
# re: Simpler Transactions
SpringFramework.NET supported this for years with its TransactionTemplate.Execute(delegate(ITransactionStatus status))

However in practice, I found it less than convenient, 1) vulnerable to the modified closure problem, 2) can't return from function within the delegate 3) can't yield within the delegate etc.

AOP (w/ Transactional attribute) is the most convenient way. But using is the most universal. I agree that having to commit transaction is a pain.
Requesting Gravatar... Oskar Aug 19, 2009 3:01 PM
# re: Simpler Transactions
I use this approach everywhere there's boilerplate resource handling involved: transactions, caching, http clients, as clients, etc. I'm not sure it qualifies as a pattern; It's only a callback parameter.
Requesting Gravatar... Joe Chung Aug 19, 2009 3:09 PM
# re: Simpler Transactions
Nitpicking here but instead of

if(SaveWorkToDatabaseSuccessful()) {
return true;
}
return false;

Why not

return SaveWorkToDatabaseSuccessful();
Requesting Gravatar... Anders Lybecker Aug 19, 2009 4:33 PM
# re: Simpler Transactions
The Transaction.Do is similar to what Microsoft Research came up with when transactional memory - STM.NET (msdn.microsoft.com/en-us/devlabs/ee334183.aspx)

They use:
Atomic.Do(()=>
{
i = 1;
});

:-)
Anders
Requesting Gravatar... Lee Englestone Aug 19, 2009 4:37 PM
# re: Simpler Transactions
Very Interesting

-- Lee
Requesting Gravatar... Patrik Hägne Aug 19, 2009 4:42 PM
# re: Simpler Transactions
This is a technique I've been using for ages, coming from a functional background and it's great. I blogged about this pattern quite some time ago ondevelopment.blogspot.com/.../...e-functions.html, to me it's about composition, it's not about saving a line of code or two. The forgetting about closing the scope will be caught by your tests. Not only as Bellware says by functional tests but by unit tests as well as far as I'm concerned. http://legendtransactions.codeplex.com/
Requesting Gravatar... Harry M Aug 19, 2009 5:27 PM
# re: Simpler Transactions
Reminds me of my "Try catch in a single line of code" post, which wasn't a great idea in retrospect, evn if people liked it. www.adverseconditionals.com/.../...ne-of-code.html

The syntax already seems easy enough to use with TransactionScope. If your policy is to use this instead of TransactionScope, you now have a maintenance issue of making sure all your code can access. it. Another one for the .Commons library?
Requesting Gravatar... Luis Abreu Aug 19, 2009 5:34 PM
# re: Simpler Transactions
I've been using similar code to that for some time now (but since I tend to use NH, I tipically use the ITransaction interface). You could also consider passing the transaction object to the action method so that it has control over the final result.
Requesting Gravatar... Vito Botta Aug 19, 2009 6:44 PM
# re: Simpler Transactions
Looks tidy and cute, but how do you use it if you want to return the results of a query to the outer function?
I use TransactionScope also to simply get data (not only to persist changes), because this way I can set the IsolationLevel to ReadUncommitted and have a behaviour similar to NOLOCK. In many cases this Isolation Level is perfectly OK for me and by doing this I have seen ~20/25 faster queries.

Your little snippet is cute, but I can I use it in this case?

Say I have now something like

using (TransactionScope transaction = new TransactionScope( TransactionScopeOption.Required, new TransactionOptions{ IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted}))
{

...

return (from ....);

}

Which is OK. But if I use your snippet, I have something like

Transaction.Do(() => {

return ..my query...

});

I can add of course an overload to be able to specify the isolation level, but in this case a boolean is expected instead of the results of my query.
Requesting Gravatar... RichB Aug 19, 2009 8:24 PM
# re: Simpler Transactions
I wrote the same thing recently for an enterprise system I work on. The prototypes are:

public static T ExecuteInTransaction<T>(this ISession session, Func<T> lambda)
and
public static void ExecuteInTransaction(this ISession session, Action lambda)

Note:
1) They are extension methods on NHibernate's ISession
2) There are 2 methods: one allows you to return the result of the lambda, the other is a void result.
Requesting Gravatar... Steve Aug 19, 2009 8:30 PM
# re: Simpler Transactions
@Vito:
What a stupid comment, you are using the transaction without committing (just reading) so you wouldn't need this at all...
Requesting Gravatar... sean Aug 19, 2009 9:14 PM
# re: Simpler Transactions
Why would you do this instead of writing a stored procedure that manages the transaction itself?

There is only one case in which I have found stored procedures to be... difficult... to use, and that is when one of my logical parameters is an array of values. Tag querying is such a problem, but there are definitely database-centric ways around it that do not require writing SQL in client code strings somewhere.
Requesting Gravatar... yemek tarifleri Aug 19, 2009 9:35 PM
# re: Simpler Transactions
If transaction failure a common I think there is another issue there.
Throwing exception is better for me.
Requesting Gravatar... Javier Lozano Aug 20, 2009 12:06 AM
# re: Simpler Transactions
I really like the simplicity and exactness of the code. One thing, let's not add a Transaction ActionFilterAttribute to MVC. :)
Requesting Gravatar... David Meyer Aug 20, 2009 4:54 AM
# re: Simpler Transactions
I've used this too, but with a custom system I designed very similar to System.Transactions to implement transactionality when using a specific third-party library.

I agree that to save one line of code may not be worth other considerations. But I have also forgotten to commit transactions, which is a bigger problem. Currently, if you forget to do this, it will not show up as a compile-time or run-time error. It will only have the effect of never commiting that transaction. But even assuming that you always write a functional test to verify the code, wouldn't it be better to catch it sooner? Say, at compile-time? Especially since some systems can have functional tests that take a long time to execute.

Basically, the best solution would be to enforce in the language that before execution control leaves the block, the transaction has to be explicitly either committed or rolled back. This could easily be done in your solution by using Func<TransactionResult> instead of Action for the delegate (where TransactionResult is just an enumeration, could be called soemthing else), which would require the delegate to return whether or not to commit or rollback the transaction before it completes.

Or the problem could be solved even simpler by incorporating the fact that it will be committed into the wording of the function.
Requesting Gravatar... Pat Gannon Aug 20, 2009 5:40 AM
# re: Simpler Transactions
I like how the code looks, but with regard to applying this approach broadly: how could you inject a mock or a fake of TransactionScope from a unit test (which doesn't touch the DB)? There are scenarios where all of the DB updates resulting from a particular piece of business logic should be applied together in a transaction, and testing such logic without touching the database is ideal IMO.

Using TransactionScope directly, you could inject a TransactionScopeBuilder (which could be mocked) and then use that to instantiate your TransactionScope. You could use the same approach with your Transaction.Do (and pass in the builder to the Do call), but it might make for somewhat awkward syntax, which might reduce the usefulness of this approach.
Requesting Gravatar... Haacked Aug 20, 2009 6:32 AM
# re: Simpler Transactions
@sean Several reasons.

1. You're not using stored procs but using some sort of OR/M.
2. You're doing a distributed transaction across multiple databases or data stores.
3. You're writing code that needs to be database agnostic (like a product which runs against different databases).
Requesting Gravatar... Hemanshu Bhojak Aug 20, 2009 3:07 PM
# re: Simpler Transactions
If I am returning true or false I will rather use transaction.complete().

In case I want to swap a function in and out of a transaction I find your solution useful as it is transaction independent.

So I simply do Transaction.do(myfunc) if I want it to run in a transaction.

It does make it simple in some cases. :)
Requesting Gravatar... Vito Botta Aug 20, 2009 5:54 PM
# re: Simpler Transactions
@Steve

If you had actually read my "stupid" comment before adding your "clever" one, you would -hopefully- understood why I use TransactionScope, in some cases, also to retrieve data.
It's about avoid the locking when this is OK as this helps speed up your queries.

Which part of

"I use TransactionScope also to simply get data (not only to persist changes), BECAUSE this way I can set the IsolationLevel to ReadUncommitted and have a behaviour similar to NOLOCK. In many cases this Isolation Level is perfectly OK for me and by doing this I have seen ~20/25 FASTER queries"

wasn't clear enough?
Requesting Gravatar... andyclap Aug 20, 2009 8:02 PM
# re: Simpler Transactions
I've been using this for a while, not for compactness or to guard against forgetting to complete, but for separation of concerns.
I don't want to know how to run a transaction, all I want to know is that a bit of work should be atomic, viz (c#2):

public void DoStuffAndOtherStuffTogether()
{
atomicCoordinator.Do(delegate
{
stuff();
otherstuff();
});
}

Stems from adapting a project using fugly dbConnection transactions to using TransactionScope. And it helped when testing as I can set up a mock to ensure a bit of work was atomic rather than trying to fail a bit of the transaction and testing it all rolled back.

@sean - sprocs vs app code is a whole different debate!

@vito - you could use this way of doing things too:

MyStuff GetStuff()
{
return uncommittedOptimisationIsFineForThis.FetchOf<MyStuff>(delegate
{
return GetMyStuff();
});
}

Means that if you need to change technologies, the thing that knows how to apply uncomitted optimisations via a transaction scope can decide whether to use it or not (or use a different technique), rather than your code.

The messier problem as zvolkov mentioned above is c#'s closures, you have to assume the delegate is going to be called and forgotten, and turn off the warning, hey ho.
Requesting Gravatar... Thanigainathan Aug 20, 2009 9:58 PM
# re: Simpler Transactions
That sounds good. But during the nested transactions does this behaves equally ?

Thanks,
Thani
Requesting Gravatar... Pita.O Aug 24, 2009 7:06 AM
# re: Simpler Transactions
@Thanigainathan: This is really the System.Transactions imperative call leveraging lambda to void repeating a single, required line of code. Nested transaction scopes always vote to commit but do not commit on their own. Only top level scope.Complete() does the commit. This construct will work the same way.

I saw this construct once (forgotten where) and thought it was cool ... It doesn't just save one line of code. It save a few more: boiler-plate IConnectionString, IDatabaseGateway, ResultDto (return value) construct that is repeated everywhere in the Tasks layer.
Requesting Gravatar... Matt Aug 27, 2009 2:11 AM
# re: Simpler Transactions
I recently wrote a short article on a more generic approach of wrapping up "using" statements like this. You can check it out here: craftycoders.com/.../...xtension-Methods-in-C.aspx
Requesting Gravatar... Rick Dailey Aug 31, 2009 5:20 AM
# re: Simpler Transactions
This reminds me of my DataBind helper (because for some reason, I feel like DataBind is a single op 90% of the time).

public static void DataBind(this BaseDataBoundControl control, object dataSource) {
control.DataSource = dataSource;
control.DataBind();
}
Requesting Gravatar... Norville Sep 18, 2009 5:04 AM
# re: Simpler Transactions
Why do people feel the need to abstract things that don't need abstracting? For 3 lines of code, and you have intellisense, is it really that hard? Think of the poor shmuck (typically me) that has to come in and maintain/fix it...

If you want to save space, then stop using braces for one line IF statements. At least I can easily understand. :-P

(I actually do like the blog, good info even if a little abstract.)

What do you have to say?

(will show your gravatar)
Please add 4 and 3 and type the answer here: