v00d00
v00d00

Reputation: 3265

The common way to work with transactions in C#

How are you using transactions in your code?

The old good way was to do something like that:

try
{
    IDbTransaction tx = Connection.BeginTransaction();
    perform_work1
    perform_work2
    perform_work3
    tx.Commit();

}
catch(DbException)
{
   tx.Rollback();
   throw;
}

But then you realise that you want to add DbExceptin logging to your software, and should, replace any appearance of transaction related code.

The first idea is to make somethig similar to this:

public static class SafeCallerProxy
    {
        public delegate T ResultativeAction<T>();

        public static T ExecuteWithResult<T>(IDbConnection conn, ResultativeAction<T> action)
        {
            using(IDbTransaction tx = conn.BeginTransaction())
            {
                try
                {
                    T result = action();
                    tx.Commit();
                    return result;
                }
                catch (System.Data.DataException)
                {
                    tx.Rollback();
                    throw;
                }
            }
        }

        public static void ExecuteAction(IDbConnection conn, Action action)
        {
            using (IDbTransaction tx = conn.BeginTransaction())
            {
                try
                {
                    action();
                    tx.Commit();
                }
                catch (System.Data.DataException)
                {
                    tx.Rollback();
                    throw;
                }
            }
        }
    }

usage

SafeCallerProxy.ExecuteAction(connection, () => 
{
  DoWork1();
  DoWork2();
  DoWork3();
}
);

And I think that I am reinventing bycicle here. Please give an example of good code which incapsulates transaction mechanism,

Sory for my English.

Upvotes: 0

Views: 739

Answers (3)

Dr. Wily&#39;s Apprentice
Dr. Wily&#39;s Apprentice

Reputation: 10280

Unless I'm mistaken, I think that you can assume that a transaction object implementing the IDbTransaction interface will perform a rollback if it is disposed prior to calling the Commit method. Granted, that is not a guarantee, but I think it would be a poor implementation if not implemented that way.

Given that, I would write your example simply as the following:

        using (var tx = connection.BeginTransaction())
        {
            DoWork1();
            DoWork2();
            DoWork3();
            tx.Commit();
        }

if I needed to catch and log database exceptions, then I would wrap the entire using block in a try/catch:

        try
        {
            using (var tx = connection.BeginTransaction())
            {
                DoWork1();
                DoWork2();
                DoWork3();
                tx.Commit();
            }
        }
        catch (DataException ex)
        {
            // log ex
        }

Upvotes: 1

Darin Dimitrov
Darin Dimitrov

Reputation: 1039438

Personally I use NHibernate with Spring.NET which has AOP support so I am basically defining in an external configuration file which are the methods which I would like to be executed under a SQL transaction. Those would normally be my service methods which in term might call multiple data access methods that I would like to run in a single transaction.

I consider that transaction management is a crosscutting concern and shouldn't be mixed with the data access code as it pollutes it. Spring.NET takes care of generating runtime proxies and injects the proper transaction handling code.

Upvotes: 1

StriplingWarrior
StriplingWarrior

Reputation: 156728

I use LINQ to Entities, which handles the transactions for me. I imagine it would be pretty easy to add automatic logging using a T4 template.

Upvotes: 1

Related Questions