Chapter 21. Object Relational Mapping (ORM) data access

21.1. Introduction

The Spring Framework provides integration with NHibernate in terms of resource management, DAO implementation support, and transaction strategies. For example for NHibernate, there is first-class support with lots of IoC convenience features, addressing many typical NHibernate integration issues. All of these support packages for O/R (Object Relational) mappers comply with Spring's generic transaction and DAO exception hierarchies. There are usually two integration styles: either using Spring's DAO 'templates' or coding DAOs against the 'plain' NHibernate APIs. In both cases, DAOs can be configured through Dependency Injection and participate in Spring's resource and transaction management.

You can use Spring's support for NHibernate without needing to use Spring IoC or transaction management functionality. The NHibernate support classes can be used in typical 3rd party library style. However, usage inside a Spring IoC container does provide additional benefits in terms of ease of configuration and deployment; as such, most examples in this section show configuration inside a Spring container.

Some of the benefits of using the Spring Framework to create your ORM DAOs include:

  • Ease of testing. Spring's IoC approach makes it easy to swap the implementations and config locations of Hibernate SessionFactory instances, ADO.NET DbProvider instances, transaction managers, and mapper object implementations (if needed). This makes it much easier to isolate and test each piece of persistence-related code in isolation.

  • Common data access exceptions. Spring can wrap exceptions from your O/R mapping tool of choice, converting them from proprietary exceptions to a common runtime DataAccessException hierarchy. You can still trap and handle exceptions anywhere you need to. Remember that ADO.NET exceptions (including DB specific dialects) are also converted to the same hierarchy, meaning that you can perform some operations with ADO.NET within a consistent programming model.

  • General resource management. Spring application contexts can handle the location and configuration of Hibernate ISessionFactory instances, ADO.NET DbProvider instances and other related resources. This makes these values easy to manage and change. Spring offers efficient, easy and safe handling of persistence resources. For example: related code using NHibernate generally needs to use the same NHibernate Session for efficiency and proper transaction handling. Spring makes it easy to transparently create and bind a Session to the current thread, either by using an explicit 'template' wrapper class at the code level or by exposing a current Session through the Hibernate SessionFactory (for DAOs based on plain Hibernate 1.2 API). Thus Spring solves many of the issues that repeatedly arise from typical NHibernate usage, for any transaction environment (local or distributed).

  • Integrated transaction management. Spring allows you to wrap your O/R mapping code with either a declarative, AOP style method interceptor, or an explicit 'template' wrapper class at the code level. In either case, transaction semantics are handled for you, and proper transaction handling (rollback, etc) in case of exceptions is taken care of. As discussed below, you also get the benefit of being able to use and swap various transaction managers, without your Hibernate/ADO.NET related code being affected: for example, between local transactions and distributed, with the same full services (such as declarative transactions) available in both scenarios. As an additional benefit, ADO.NET-related code can fully integrate transactionally with the code you use to do O/R mapping. This is useful for data access that's not suitable for O/R mapping which still needs to share common transactions with ORM operations.

The NHibernate Northwind example in the Spring distribution shows a NHibernate implementation of a persistence-technology agnostic DAO interfaces. (In the upcoming RC1 release the SpringAir example will demonstrate an ADO.NET and NHibernate based implementation of technology agnostic DAO interfaces.) The NHibernate Northwind example serves as a working sample application that illustrates the use of NHibernate in a Spring web application. It also leverages declarative transaction demarcation with different transaction strategies.

Both NHibernate 1.0 and NHibernate 1.2 are supported. Differences relate to the use of generics and new features such as contextual sessions. For information on the latter, refer to the section Implementing DAOs based on the plain NHibernate API. The NHibernate 1.0 support is in the assembly Spring.Data.NHibernate and the 1.2 support is in the assembly Spring.Data.NHibernate12

At the moment the only ORM supported in NHibernate, but others can be integrated with Spring (in as much as makes sense) to offer the same value proposition.

21.2. NHibernate

We will start with a coverage of NHibernate in a Spring environment, using it to demonstrate the approach that Spring takes towards integrating O/R mappers. This section will cover many issues in detail and show different variations of DAO implementations and transaction demarcations. Most of these patterns can be directly translated to all other supported O/R mapping tools.

The following discussion focuses on Hibernate 1.0.4, the major differences with NHibernate 1.2 being the ability to participate in Spring transaction/session management via the normal NHibernate API instead of the 'template' approach. Spring supports both NHibernate 1.0 and NHibernate 1.2 via separate .dlls with the same internal namespace.

21.2.1. Resource management

Typical business applications are often cluttered with repetitive resource management code. Many projects try to invent their own solutions for this issue, sometimes sacrificing proper handling of failures for programming convenience. Spring advocates strikingly simple solutions for proper resource handling, namely IoC via templating; for example infrastructure classes with callback interfaces, or applying AOP interceptors. The infrastructure cares for proper resource handling, and for appropriate conversion of specific API exceptions to a common infrastructure exception hierarchy. Spring introduces a DAO exception hierarchy, applicable to any data access strategy. For direct ADO.NET, the AdoTemplate class mentioned in a previous section cares for connection handling, and for proper conversion of ADO.NET data access exceptions (not even singly rooted in .NET 1.1) to Spring's DataAccessException hierarchy, including translation of database-specific SQL error codes to meaningful exception classes. It supports both distributed and local transactions, via respective Spring transaction managers.

Spring also offers Hibernate support, consisting of a HibernateTemplate analogous to AdoTemplate, a HibernateInterceptor, and a Hibernate transaction manager. The major goal is to allow for clear application layering, with any data access and transaction technology, and for loose coupling of application objects. No more business service dependencies on the data access or transaction strategy, no more hard-coded resource lookups, no more hard-to-replace singletons, no more custom service registries. One simple and consistent approach to wiring up application objects, keeping them as reusable as possible. All the individual data access features are usable on their own but integrate nicely with Spring's application context concept, providing XML-based configuration and cross-referencing of plain object instances that don't need to be Spring-aware. In a typical Spring application, many important objects are plain CLR objects: data access templates, data access objects (that use the templates), transaction managers, business services (that use the data access objects and transaction managers), ASP.NET web pages (that use the business services),and so on.

21.2.2. Transaction Management

While NHibernate offers an API for transaction management you will quite likely find the benefits of using Spring's generic transaction management features to be more compelling to use, typically for use of a declarative programming model for transaction demarcation and easily mixing ADO.NET and NHibernate operations within a single transaction. See the chapter on transaction management for more information on Spring's transaction management features. There are two choices for transaction management strategies, one based on the NHibernate API and the other the .NET 2.0 TransactionScope API.

The first strategy is encapsulated in the class Spring.Data.NHibernate.HibernateTransactionManager in both the Spring.Data.NHibernate namespace. This strategy is preferred when you are using a single database. ADO.NET operations can also participate in the same transaction, either by using AdoTemplate or by retrieving the ADO.NET connection/transaction object pair stored in thread local storage when the transaction begins. Refer to the documentation of Spring's ADO.NET framework for more information on retrieving and using the connection/transaction pair without using AdoTemplate. You can use the HibernateTransactionManager and associated classes such as SessionFactory, HibernateTemplate directly as you would any third party API, however they are most commonly used through Spring's XML configuration file to gain the benefits of easy configuration for a particular runtime environment and as the basis for the configuration of a data access layer also configured using XML. An XML fragment showing the declaration of HibernateTransactionManager is shown below.

  <object id="transactionManager"
        type="Spring.Data.NHibernate.HibernateTransactionManager, Spring.Data.NHibernate">

    <property name="DbProvider" ref="DbProvider"/>
    <property name="SessionFactory" ref="MySessionFactory"/>

  </object>

The important property of HibernateTransactionManager are the references to the DbProvider and the Hibernate ISessionFactory. For more information on the DbProvider, refer to the chapter DbProvider and the following section on SessionFactory set up.

The second strategy is to use the class Spring.Data.TxScopeTransactionManager that uses .NET 2.0 System.Transaction namespace and its corresponding TransactionScope API. This is preferred when you are using multiple transactional resources, such as multiple databases. Note that due to changes in the manner in which NHibernate manages its own transactions introduced in NHibernate 2.1.2 (and later), when using NHibernate 2.1.2 (and later) in the context of the .NET System.Transaction class and its TransactionScope API Spring.NET users are advised to use the Spring.Data.HibernateTxScopeTransactionManager class which is specifically designed to manage the new NHibernate transcational model when used in the context of the System.Transaction API. The API of the Spring.Data.HibernateTxScopeTransactionManager class is functionally equivalent to that of the Spring.Data.HibernateTransactionManager class but it is designed to cooperate with the .NET System.Transaction TransactionScope API for NHibernate 2.1.2 (and later).

All of these strategies associate one Hibernate Session for the scope of the transaction (scope in the general demarcation sense, not System.Transaction sense). If there is no transaction then a new Session will be opened for each operation. The exception to this rule is when using the OpenSessionInViewModule in a web application in single session mode (see Section 21.2.8, “Web Session Management”). In this case the session will be created on the start of the web request and closed on the end of the request. Note that the session's flush mode will be set to FlushMode.NEVER at the start of the request. If a non-readonly transaction is performed, then during the scope of that transaction processing the flush mode will be changed to AUTO, and then set back to NEVER at the end of the transaction scope so that any changes to objects associated with the session during rendering will not be persisted back to the database when the session is closed at the end of the web request.

21.2.3. SessionFactory set up in a Spring container

To avoid tying application objects to hard-coded resource lookups, Spring allows you to define resources like a DbProvider or a Hibernate SessionFactory as objects in an application context. Application objects that need to access resources just receive references to such pre-defined instances via object references (the DAO definition in the next section illustrates this). The following excerpt from an XML application context definition shows how to set up Spring's ADO.NET DbProvider and a Hibernate SessionFactory on top of it:

<objects xmlns="http://www.springframework.net"
         xmlns:db="http://www.springframework.net/database">


  <!-- Property placeholder configurer for database settings -->

  <object type="Spring.Objects.Factory.Config.PropertyPlaceholderConfigurer, Spring.Core">
    <property name="ConfigSections" value="databaseSettings"/>
  </object>

  <!-- Database and NHibernate Configuration -->

  <db:provider id="DbProvider"
                   provider="SqlServer-1.1"
                   connectionString="Integrated Security=false; Data Source=(local);Integrated Security=true;Database=Northwin;User ID=springqa;Password=springqa;"/>



  <object id="MySessionFactory" type="Spring.Data.NHibernate.LocalSessionFactoryObject, Spring.Data.NHibernate">
    <property name="DbProvider" ref="DbProvider"/>
    <property name="MappingAssemblies">
      <list>
        <value>Spring.Northwind.Dao.NHibernate</value>
      </list>
    </property>
    <property name="HibernateProperties">
      <dictionary>

        <entry key="hibernate.connection.provider"
               value="NHibernate.Connection.DriverConnectionProvider"/>

        <entry key="hibernate.dialect"
               value="NHibernate.Dialect.MsSql2000Dialect"/>

        <entry key="hibernate.connection.driver_class"
               value="NHibernate.Driver.SqlClientDriver"/>

      </dictionary>
    </property>

  </object>

</objects>

Many of the properties on LocalSessionFactoryObject are those you will commonly configure, for example the property MappingAssemblies specifies a list of assemblies to seach for hibernate mapping files. The property HibernateProperies are the familiar NHibernate properties used to set typical options such as dialect and driver class. The location of NHibernate mapping information can also be specified using Spring's IResource abstraction via the property MappingResources. The IResource abstraction supports opening an input stream from assemblies, file system, and http(s) based on a Uri syntax. You can also leverage the extensibility of IResource and thereby allow NHibernate to obtain its configuration information from locations such as a database or LDAP.For other properties you can configure them as you normal using the file hibernate.cfg.xml and refer to it via the property ConfigFileNames. This property is a string array so multiple configuration files are supported.

There are other properties in LocalSessionFactoryObject that relate to the integration of Spring with NHibernate. The property ExposeTransactionAwareSessionFactory is discussed below and allows you to use Spring's declarative transaction demarcation functionality with the standard NHibernate API (as compared to using HibernateTemplate).

The property DbProvider is used to infer two NHibernate configurations options.

  • Infer the connection string, typically done via the hibernate property "hibernate.connection.connection_string".

  • Delegate to the DbProvider itself as the NHibernate connection provider instead of listing it via property hibernate.connection.provider via HibernateProperties.

If you specify both the property hibernate.connection.provider and DbProvider (as shown above) the configuration of the property hibernate.connection.provider is used and a warning level message is logged. If you use Spring's DbProvider as the NHibernate connection provider then you can take advantage of IDbProvider implementations that will let you change the connection string at runtime such as UserCredentialsDbProvider and MultiDelegatingDbProvider.

[Note]Note

UserCredentialsDbProvider and MultiDelegatingDbProvider only change the connection string at runtime based on values in thread local storage and do not clear out the Hibernate cache that is unique to each ISessionFactory instance. As such, they are only useful for selecting at runtime a single database instance. Cleaning up an existing session factory when switching to a new database is left to user code.

21.2.3.1. Creating a new SessionFactory per Connection String with DelegatingLocalSessionFactory Object

Beginning with Spring.NET 1.3.1 there is direct support for creating a new session factory per connection string (assuming the same mapping files can be used across all databases connections). To support this functionality, DelegatingLocalSessionFactoryObject subclasses LocalSessionFactoryObject and overrides the method ISessionFactory NewSessionFactory(Configuration config) so that it returns an implementation of ISessionFactory that selects among multiple instances based on values in thread local storage, much like the implementation of MultiDelegatingDbProvider. Note that due to variations in the NHibernate project's ISessionFactory API, this approach is only supported under NHibernate 2.1.2 and NHibernate 3.0

21.2.3.2. Using FluentNHibernate to configure mappings with LocalSessionFactoryObject

Direct support for configuration of NHibernate mapping files using FluentNHibernate will be included in a future release. Until then, to see how you can extend LocalSessionFactoryObject to suppport using FluentNHibernate follow the instructions on Benny Michielson's blog post here.

21.2.3.3. Spring's IByteCodeProvider implementation

Introduced in Hibernate 2.1 is support for dependency injection of hibernate managed objects via the IBytecodeProvider extension point. As of Spring 1.3 provides Spring.Data.NHibernate.Bytecode.BytecodeProvider as the default IBytecodeProvider implementation when using LocalSessionFactory object to configure an ISessionFactory. To use a different IBytecodeProvider configure it via the standard the Hibernate means, using App.confg or Web.config via the element <bytecode-provider type="..."/> inside the <hibernate-configuration> section or progammatically by setting Environment.BytecodeProvider.

21.2.4. Implementing DAOs based on plain Hibernate 1.2/2.x API

Hibernate 1.2 introduced a feature called "contextual Sessions", where Hibernate itself manages one current ISession per transaction. This is roughly equivalent to Spring's synchronization of one Hibernate Session per transaction. A corresponding DAO implementation looks like as follows, based on the plain Hibernate API:

public class ProductDaoImpl implements IProductDao {

    private SessionFactory sessionFactory;

    public ISessionFactory SessionFactory
    {
        get { return sessionFactory; }
        set { sessionFactory = value; }
    }

    public IList<Product> LoadProductsByCategory(String category) {
        return SessionFactory.GetCurrentSession()
                .CreateQuery("from test.Product product where product.category=?")
                .SetParameter(0, category)
                .List<Product>();
    }
}


public class HibernateCustomerDao : ICustomerDao {

  private ISessionFactory sessionFactory;

  public ISessionFactory SessionFactory
  {
      set { sessionFactory = value; }
  }

  public Customer SaveOrUpdate(Customer customer)
  {
      sessionFactory.GetCurrentSession().SaveOrUpdate(customer);
      return customer;
  }
}

The above DAO follows the Dependency Injection pattern: it fits nicely into a Spring IoC container, just like it would if coded against Spring's HibernateTemplate. Of course, such a DAO can also be set up in plain C# (for example, in unit tests): simply instantiate it and call SessionFactory property with the desired factory reference. As a Spring object definition, it would look as follows:

<objects>

  <object id="CustomerDao" type="Spring.Northwind.Dao.NHibernate.HibernateCustomerDao, Spring.Northwind.Dao.NHibernate">
    <property name="sessionFactory" ref="MySessionFactory"/>
  </object>

</objects>

The SessionFactory configuration to support this programming model can be done two ways, both via configuration of Spring's LocalSessionFactoryObject. You can enable the use of Spring's implementation of the NHibernate extension interface, ICurrentSessionContext, by setting the property 'ExposeTransactionAwareSessionFactory' to true on LocalSessionFactoryObject. This is just a short-cut for setting the NHibernate property current_session_context_class with the name of the implementation class to use.

The first way is shown below

<object id="sessionFactory" type="Spring.Data.NHibernate.LocalSessionFactoryObject, Spring.Data.NHibernate12">

  <property name="ExposeTransactionAwareSessionFactory" value="true" />

   <!-- other configuration settings omitted -->

</object>

Which is simply a shortcut for the following configuration

<object id="sessionFactory" type="Spring.Data.NHibernate.LocalSessionFactoryObject, Spring.Data.NHibernate12">

   <!-- other configuration settings omitted -->

   <property name="HibernateProperties">
     <dictionary>

       <!-- other dictionary entries omitted -->

       <entry key="hibernate.current_session_context_class"
              value="Spring.Data.NHibernate.SpringSessionContext, Spring.Data.NHibernate12"/>

    </dictionary>
   </property>

</object>

The main advantage of this DAO style is that it depends on the Hibernate API only; no import of any Spring class is required. This is of course appealing from a non-invasiveness perspective, and will no doubt feel more natural to Hibernate developers.

21.2.4.1. Exception Translation

However, the DAO implemenation as shown throws plain HibernateException which means that callers can only treat exceptions as generally fatal - unless they want to depend on Hibernate's own exception hierarchy. Catching specific causes such as an optimistic locking failure is not possible without tying the caller to the implementation strategy. This trade off might be acceptable to applications that are strongly Hibernate-based and/or do not need any special exception treatment. As an alternative you can use Spring's exception translation advice to convert the NHibernate exception to Spring's DataAccessException hierarchy.

Spring offers a solution allowing exception translation to be applied transparently through the [Repository] attribute:

[Repository]
public class HibernateCustomerDao : ICustomerDao {

  // class body here

}

and register an exception translation post processor.

<objects>

  <!-- configure session factory (omittied for brevity) -->

  <!-- Exception translation object post processor -->
  <object type="Spring.Dao.Attributes.PersistenceExceptionTranslationPostProcessor, Spring.Data"/>

  <!-- Same DAO configuration as before -->
  <object id="CustomerDao" type="Spring.Northwind.Dao.NHibernate.HibernateCustomerDao, Spring.Northwind.Dao.NHibernate">
    <property name="sessionFactory" ref="MySessionFactory"/>
  </object>

</objects>

The postprocessor will automatically look for all exception translators (implementations of the IPersistenceExceptionTranslator interface) and advise all object marked with the [Repository] attribute so that the discovered translators can intercept and apply the appropriate translation on the thrown exceptions. Spring's LocalSessionFactory object implements the IPersistenceExceptionTranslator interface and performs the same exception translation as was done when using HibernateTemplate.

The [Repository] attribute is definedin the Spring.Data assembly, however it is used as a 'marker' attribute, and you can provide your own if you would like to avoid coupling your DAO implementation to a Spring attribute. This is done by setting PersistenceExceptionTranslationPostProcessor's property RepositoryAttributeType to your own attribute type.

[Note]Note

In summary: DAOs can be implemented based on the plain Hibernate 1.2/2.0 API, while still being able to participate in Spring-managed transactions and exception translation.

21.2.5. Declarative transaction demarcation

Alternatively, one can use Spring's declarative transaction support, which essentially enables you to replace explicit transaction demarcation API calls in your C# code with an AOP transaction interceptor configured in a Spring container. You can either externalize the transaction semantics (like propagation behavior and isolation level ) in a configuration file or use the Transaction attribute on the service method to set the transaction semantics.

An example showing attribute driven transaction is shown below

<objects>

  <object id="TransactionManager"
        type="Spring.Data.NHibernate.HibernateTransactionManager, Spring.Data.NHibernate">

    <property name="DbProvider" ref="DbProvider"/>
    <property name="SessionFactory" ref="MySessionFactory"/>

  </object>

  <!-- DAO definition not listed, see above for an example. -->

  <object id="FulfillmentService" type="Spring.Northwind.Service.FulfillmentService, Spring.Northwind.Service">
    <property name="CustomerDao" ref="CustomerDao"/>
    <property name="OrderDao" ref="OrderDao"/>
    <property name="ShippingService" ref="ShippingService"/>
  </object>

  <!-- Import 'standard xml' configuration for attribute driven declarative tx management -->
  <import resource="DeclarativeServicesAttributeDriven.xml"/>

</objects>

Note that with the new transaction namespace, you can replace the importing of DeclarativeServicesAttributeDriven.xml with the following single line, <tx:attribute-driven/> that more clearly expresses the intent as compared to the contents of DeclarativeServicesAttributeDriven.xml.

<objects xmlns="http://www.springframework.net"
	        xmlns:tx="http://www.springframework.net/schema/tx">


  <object id="transactionManager"
        type="Spring.Data.NHibernate.HibernateTransactionManager, Spring.Data.NHibernate">

    <property name="DbProvider" ref="DbProvider"/>
    <property name="SessionFactory" ref="MySessionFactory"/>

  </object>

  <!-- DAO definition not listed, see above for an example. -->

  <object id="FulfillmentService" type="Spring.Northwind.Service.FulfillmentService, Spring.Northwind.Service">
    <property name="CustomerDao" ref="CustomerDao"/>
    <property name="OrderDao" ref="OrderDao"/>
    <property name="ShippingService" ref="ShippingService"/>
  </object>


  <tx:attribute-driven/>


</objects>

The placement of the transaction attribute in the service layer method is shown below.

public class FulfillmentService : IFulfillmentService
{
  // fields and properties for dao object omitted, see above


    [Transaction(ReadOnly=false)]
    public void ProcessCustomer(string customerId)
    {

            //Find all orders for customer
            Customer customer = CustomerDao.FindById(customerId);

            foreach (Order order in customer.Orders)
            {
                //Validate Order
                Validate(order);

                //Ship with external shipping service
                ShippingService.ShipOrder(order);

                //Update shipping date
                order.ShippedDate = DateTime.Now;

                //Update shipment date
                OrderDao.SaveOrUpdate(order);

                //Other operations...Decrease product quantity... etc
            }

    }
}

If you prefer to not use attribute to demarcate your transaction boundaries, you can import a configuration file with the following XML instead of using <tx:attribute-driven/>

  <object id="TxProxyConfigurationTemplate" abstract="true"
          type="Spring.Transaction.Interceptor.TransactionProxyFactoryObject, Spring.Data">

    <property name="PlatformTransactionManager" ref="HibernateTransactionManager"/>

    <property name="TransactionAttributes">
      <name-values>
        <!-- Add common methods across your services here -->
        <add key="Process*" value="PROPAGATION_REQUIRED"/>
      </name-values>
    </property>
  </object>

Refer to the documentation on Spring Transaction management for configuration of other features, such as rollback rules.

21.2.6. Programmatic transaction demarcation

Transactions can be demarcated in a higher level of the application, on top of such lower-level data access services spanning any number of operations. There are no restrictions on the implementation of the surrounding business service here as well, it just needs a Spring PlatformTransactionManager. Again, the latter can come from anywhere, but preferably as an object reference via a TransactionManager property - just like the productDAO should be set via a setProductDao(..) method. The following snippets show a transaction manager and a business service definition in a Spring application context, and an example for a business method implementation.

<objects>

  <object id="TransactionManager"
        type="Spring.Data.NHibernate.HibernateTransactionManager, Spring.Data.NHibernate">

    <property name="DbProvider" ref="DbProvider"/>
    <property name="SessionFactory" ref="MySessionFactory"/>

  </object>

  <!-- DAO definition not listed, see above for an example. -->

  <object id="FulfillmentService" type="Spring.Northwind.Service.FulfillmentService, Spring.Northwind.Service">
    <property name="CustomerDao" ref="CustomerDao"/>
    <property name="OrderDao" ref="OrderDao"/>
    <property name="ShippingService" ref="ShippingService"/>
    <property name="TransactionManager" ref="TransactionManager"/>
  </object>


</objects>
public class FulfillmentService : IFulfillmentService

    private TransactionTemplate transactionTemplate;

    private IProductDao productDao;

    private ICustomerDao customerDao;

    private IOrderDao orderDao;

    private IShippingService shippingService;


    public TransactionManager TransactionManager
    {
       set { transactionTemplate = new TransactionTemplate(value);
    }
    public void ProcessCustomer(string customerId)
    {
      tt.Execute(delegate(ITransactionStatus status) 
          {
            //Find all orders for customer
            Customer customer = CustomerDao.FindById(customerId);
            foreach (Order order in customer.Orders)
            {
                //Validate Order
                Validate(order);

                //Ship with external shipping service
                ShippingService.ShipOrder(order);

                //Update shipping date
                order.ShippedDate = DateTime.Now;

                //Update shipment date
                OrderDao.SaveOrUpdate(order);

                //Other operations...Decrease product quantity... etc
            }
            return null;
          });
    }
}

21.2.7. Transaction management strategies

Both TransactionTemplate and TransactionInterceptor (not yet seen explicitly in above configuration, TransactionProxyFactoryObject uses a TransactionInterceptor, you would have to specify it explicitly if you were using an ordinary ProxyFactoryObject.) delegate the actual transaction handling to a PlatformTransactionManager instance, which can be a HibernateTransactionManager (for a single Hibernate SessionFactory, using a ThreadLocal Session under the hood) or a TxScopeTransactionManager (delegating to MS-DTC for distributed transaction) for Hibernate applications. You could even use a custom PlatformTransactionManager implementation. So switching from native Hibernate transaction management to TxScopeTransactionManager, such as when facing distributed transaction requirements for certain deployments of your application, is just a matter of configuration. Simply replace the Hibernate transaction manager with Spring's TxScopeTransactionManager implementation. Both transaction demarcation and data access code will work without changes, as they just use the generic transaction management APIs.

For distributed transactions across multiple Hibernate session factories, simply combine TxScopeTransactionManager as a transaction strategy with multiple LocalSessionFactoryObject definitions. Each of your DAOs then gets one specific SessionFactory reference passed into it's respective object property.

TO BE DONE
     

HibernateTransactionManager can export the ADO.NET Transaction used by Hibernate to plain ADO.NET access code, for a specific DbProvider. (matching connection string). This allows for high-level transaction demarcation with mixed Hibernate/ADO.NET data access!

21.2.8. Web Session Management

The open session in view pattern keeps the hibernate session open during page rendering so lazily loaded hibernate objects can be displayed. You configure its use by adding an additional custom HTTP module declaration as shown below

  <system.web>
    <httpModules>
      <add name="OpenSessionInView" type="Spring.Data.NHibernate.Support.OpenSessionInViewModule, Spring.Data.NHibernate"/>
    </httpModules>

...

  </system.web>

You can configure which SessionFactory the OpenSessionInViewModule will use by setting 'global' application key-value pairs as shown below. (this will change in future releases)

  <appSettings>
    <add key="Spring.Data.NHibernate.Support.OpenSessionInViewModule.SessionFactoryObjectName" value="SessionFactory"/>
  </appSettings>

The default behavior of the module is that a single session is currently used for the life of the request. Refer to the earlier section on Transaction Management in this chapter for more information on how sessions are managed in the OpenSessionInViewModule. You can also configure in the application setting the EntityInterceptorObjectName using the key Spring.Data.NHibernate.Support.OpenSessionInViewModule.EntityInterceptorObjectName and if SingleSession mode is used via the key Spring.Data.NHibernate.Support.OpenSessionInViewModule.SingleSession. If SingleSession is set to false, referred to as 'deferred close mode', then each transaction scope will use a new Session and kept open until the end of the web request. This has the drawback that the first level cache is not reused across transactions and that objects are required to be unique across all sessions. Problems can arise if the same object is associated with more than one hibernate session.

[Important]Important

By default, OSIV applies FlushMode.NEVER on every session it creates. This is because if OSIV flushed pending changes during "EndRequest" and an error occurs, all response has already been sent to the client. There would be no way of telling the client about the error.

By default this means you MUST explicitly demarcate transaction boundaries around non-readonly statements when using OSIV. For configuring transactions see Section 21.2.5, “Declarative transaction demarcation” or the Spring.Data.NHibernate.Northwind example application.

21.2.9. Session Scope

The class Spring.Data.NHibernate.Support.SessionScope allows for you to use a single NHibernate session across multiple transactions. The usage is shown below

using (new SessionScope())
{
    ... do multiple operations with a single session, possibly in multiple transactions.
}

Refer to the API documentation for information on overloaded constructor. At the end of the using block the session is automatically closed. All transactions within the scope use the same session, if you are using Spring's HibernateTemplate or using Spring's implementation of NHibernate 1.2's ICurrentSessionContext interface. See other sections in this chapter for further information on those usage scenarios.

21.2.10. Integration Testing

When using Spring's Integration Testing support, you should make sure that the hibernate session is flushed so that the database is updated, as compared to just updating the hibernate session cache. You can implement a base class as shown below to help with the integration testing

public abstract class NHibernateIntegrationTests : AbstractTransactionalSpringContextTests
{
    private SessionFactory sessionFactory;

    public ISessionFactory SessionFactory
    {
        get { return sessionFactory; }
        set { sessionFactory = value; }
    }

    protected override void OnSetUpInTransaction()
    {
       base.OnSetUpInTransaction();
       Assert.IsNotNull(SessionFactory);
       SessionFactory.GetCurrentSession().FlushMode = FlushMode.Always;
       SessionFactory.GetCurrentSession().CacheMode = CacheMode.Ignore;
    }
}