Sexy Transactions In Spring.NET

Spring.NET really has tons of handy features you can put to work in your application. One of them is its transaction management, that provides an implementation agnostic abstraction for your application. The first question you’re probably asking yourself is, why do you need to abstract away your transaction technology? The short answer is there are various ways of using transactions and different transaction technologies: ADO.NET, Enterprise Services, System.Transactions, and the different transaction implementations for other database technologies like ORMs (NHibernate). I won’t go into the detail of these, suffice to say that choosing, using and changing a transaction technology can become a complicated affair, and that Spring.NET protects your application from these ugly details. I encourage you to take a deep dive into the official Spring.NET documentation, should you want to know more about the details behind this.

What I did was, write a helper class that makes it a little easier and cleaner to use Spring.NET’s transaction management:


/// <summary>
 /// Manages database transactions by wrapping executed
 /// methods in a transaction.
 /// </summary>
 public static class Transaction
 {
 /// <summary>
 /// Executes the specified method in a transaction.
 /// </summary>
 public static void Execute(Action method, bool commitChanges = true)
 {
 // Create a new transaction
 Instantiate.New<ITransactionOperations>().Execute(delegate(ITransactionStatus transaction)
 {
 // If changes should not be committed, make
 // sure we roll back once done
 if (!commitChanges) transaction.SetRollbackOnly();
 method();
 return null;
 });
 }
 }

/// <summary>
 /// Instantiates objects based on their name.
 /// </summary>
 public static class Instantiate
 {
 #region Fields

 private static IApplicationContext context;

 #endregion

 #region Get objects from ApplicationContext

 /// <summary>
 /// Retrieves the object with the specified name.
 /// </summary>
 /// <typeparam name="T">The type of object to return.
 /// <param name="name">The name of the object.</param>
 /// <returns>A newly created object with the type specified by the name, or a singleton object if so configured.</returns>
 public static T New<T>(string name)
 {
 return (T)Context.GetObject(name);
 }

 /// <summary>
 /// Retrieves the object of the specified type.
 /// </summary>
 public static T New<T>()
 {
 return (from obj in Context.GetObjectsOfType(typeof(T)).Values.Cast().ToList()
 select obj).FirstOrDefault();
 }

 /// <summary>
 /// Retrieves the object with the specified name, and constructor arguments.
 /// </summary>
 public static T New<T>(string name, object[] arguments)
 {
 return (T)Context.GetObject(name, arguments);
 }

 #endregion

 #region Private methods

 /// <summary>
 /// Gets the context.
 /// </summary>
 /// <value>The context.</value>
 private static IApplicationContext Context
 {
 get
 {
 if (context == null)
 {
 context = ContextRegistry.GetContext();
 }

 return context;
 }
 }

 #endregion
 }

Class Instantiate

The Instantiate class is a wrapper for Spring.NET’s IApplicationContext, with a few helper methods. It provides three overloads of the method New<T>, that instantiates new objects from the ApplicationContext configuration. The most important method is New<T> without any arguments. This method simply grabs the first instance of the requested Type it finds in the ApplicationContext. The other two variations allow you to instantiate a new object with a specific id.

With the help of the Instantiate class the Transaction class will obtain the specified transaction management from Spring’s ApplicationContext.

Class Transaction

This is where all the action really happens as far as database transactions go. The Transaction class has a single Execute method, that transparently wraps any block of code in a transaction. There are a small number of things you have to do to use Spring’s transaction management:

1. First get an instance of your chosen transaction implementation.

2. Call Execute with a delegate with an ITransactionStatus argument.

3. When you’re done, you have to return something, even if it’s null.

My goal is to remove the above 3 requirements, so I can just pass a block of code through to get it wrapped in a transaction. This is exactly what Execute achieves:


Transaction.Execute(() =>
 {
 // Get a FileTypeRepository
 var fileTypeRepository = Instantiate.New();

 // Add an object
fileTypeRepository.Add(fileType);

 // Save the changes to the database
 fileTypeRepository.SaveChanges();

});

Spring.NET provides 4 transaction implementations:

  • Spring.Data.Core.AdoPlatformTransactionManager – local ADO.NET based transactions
  • Spring.Data.Core.ServiceDomainPlatformTransactionManager – distributed transaction manager from Enterprise Services
  • Spring.Data.Core.TxScopeTransactionManager – local/distributed transaction manager from System.Transactions.
  • Spring.Data.NHibernate.HibernateTransactionManager – local transaction manager for use with NHibernate or mixed ADO.NET/NHibernate data access operations.

To configure your transaction manager for the ApplicationContext you need:


<objects xmlns="http://www.springframework.net">
 <object id="transactionManager"
 type="Spring.Data.Core.TxScopeTransactionManager, Spring.Data" />
 <object id="transactionTemplate"
 type="Spring.Transaction.Support.TransactionTemplate, Spring.Data"
 autowire="constructor" />
</objects>

Spring.NET’ provides a TransactionTemplate that handles all the necessary transaction logic and resources like commits, rollbacks, and errors. It frees you from getting involved with low level transaction management details, and provides all transaction management out of the box. If you desire you can directly access a transaction manager, through an IPlatformTransactionManager interface, to manage the details of your transaction process.

TransactionTemplate implements the ITransactionOperations interface. It has a constructor that requires a IPlatformTransactionManager instance. All transaction managers implement the IPlatformTransactionManager interface. This means TransactionTemplate contains the specified transaction manager. The required transaction manager is provided to the TransactionTemplate through autowiring of the constructor’s parameters. The autowiring searches through the objects and returns the first configured object that implements the IPlatformTransactionManager interface, which is transactionManager in  our case.

Object transactionManager is an instance of TxScopeTransactionManager, that is in turn based on System.Transactions.

Transaction.Execute has a second optional parameter, commitChanges. The commitChanges argument defaults to true, so the transaction manager will always attempt to commit changes. I use it when I test my application, and I want all test data to be rolled back.

Based on the fact that it commitChanges is an optional parameter, you’ve probably figured out by now that I recompiled Spring.NET to run on .NET 4.

The example IFileTypeRepository is actually based on Entity Framework 4 with Plain Old CLR/C# Objects (POCO). Just in case you were wondering if Spring.NET’s transaction management works with Entity Framework.

Advertisements

2 Comments on “Sexy Transactions In Spring.NET”

  1. Gustavo says:

    Hi
    Where I can find your example IFileTypeRepository to download it.
    Thanks

    • openlandscape says:

      Hi Gustavo,

      Why are you looking for the source code for IFileTypeRepository? It is not really important to the transaction example, and can be replaced with any object making database calls.

      ________________________________ Jacques du Preez


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s