Reputation: 3265
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
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
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
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