From 055ebf3a05c1df9cb492db0e480648b08e889ccd Mon Sep 17 00:00:00 2001 From: markpollack Date: Fri, 31 Jul 2009 00:58:58 +0000 Subject: [PATCH] SPRNET-1104 - NHibernate 2.1 Support --- doc/reference/src/orm.xml | 448 +++++++++--------- .../NHibernate/LocalSessionFactoryObject.cs | 4 - .../NHibernate/Bytecode/BytecodeProvider.cs | 2 +- 3 files changed, 237 insertions(+), 217 deletions(-) diff --git a/doc/reference/src/orm.xml b/doc/reference/src/orm.xml index 3c82044f..c3f3ab82 100644 --- a/doc/reference/src/orm.xml +++ b/doc/reference/src/orm.xml @@ -394,158 +394,31 @@ instances based on values in thread local storage, much like the implementation of MultiDelegatingDbProvider. - -
- The <literal>HibernateTemplate</literal> +
+ Spring's IByteCodeProvider implementation - The basic programming model for templating looks as follows for - methods that can be part of any custom data access object or business - service. There are no restrictions on the implementation of the - surrounding object at all, it just needs to provide a Hibernate - SessionFactory. It can get the latter from anywhere, - but preferably as an object reference from a Spring IoC container - via - a simple SessionFactory property setter. The - following snippets show a DAO definition in a Spring container, - referencing the above defined SessionFactory, and an - example for a DAO method implementation. - - <objects> - - <object id="CustomerDao" type="Spring.Northwind.Dao.NHibernate.HibernateCustomerDao, Spring.Northwind.Dao.NHibernate"> - <property name="SessionFactory" ref="MySessionFactory"/> - </object> - -</objects> - - - - public class HibernateCustomerDao : ICustomerDao { - - private HibernateTemplate hibernateTemplate; - - public ISessionFactory SessionFactory - { - set { hibernateTemplate = new HibernateTemplate(value); } - } - - public Customer SaveOrUpdate(Customer customer) - { - hibernateTemplate.SaveOrUpdate(customer); - return customer; - } -} - - The HibernateTemplate class provides many - methods that mirror the methods exposed on the Hibernate - Session interface, in addition to a number of - convenience methods such as the one shown above. If you need access to - the Session to invoke methods that are not exposed on - the HibernateTemplate, you can always drop down to a - callback-based approach like so. - - public class HibernateCustomerDao : ICustomerDao { - - private HibernateTemplate hibernateTemplate; - - public ISessionFactory SessionFactory - { - set { hibernateTemplate = new HibernateTemplate(value); } - } - - public Customer SaveOrUpdate(Customer customer) - { - return HibernateTemplate.Execute( - delegate(ISession session) - { - // do whatever you want with the session.... - session.SaveOrUpdate(customer); - return customer; - }) as Customer; - } - -} - - Using the anonymous delegate is particularly convenient when you - would otherwise be passing various method parameter calls to the - interface based version of this callback. Furthermore, when using - generics, you can avoid the typecast and write code like the - following - - IList<Supplier> suppliers = HibernateTemplate.ExecuteFind<Supplier>( - delegate(ISession session) - { - return session.CreateQuery("from Supplier s were s.Code = ?") - .SetParameter(0, code) - .List<Supplier>(); - }); - - where code is a variable in the surrounding block, accessible - inside the anonymous delegate implementation. - - A callback implementation effectively can be used for any - Hibernate data access. HibernateTemplate will ensure - that Session instances are properly opened and - closed, and automatically participate in transactions. The template - instances are thread-safe and reusable, they can thus be kept as - instance variables of the surrounding class. For simple single step - actions like a single Find, Load, SaveOrUpdate, or Delete call, - HibernateTemplate offers alternative convenience - methods that can replace such one line callback implementations. - Furthermore, Spring provides a convenient - HibernateDaoSupport base class that provides a - SessionFactory property for receiving a - SessionFactory and for use by subclasses. In - combination, this allows for very simple DAO implementations for typical - requirements: - - public class HibernateCustomerDao : HibernateDaoSupport, ICustomerDao -{ - public Customer SaveOrUpdate(Customer customer) - { - HibernateTemplate.SaveOrUpdate(customer); - return customer; - } -} -
- -
- Implementing Spring-based DAOs without callbacks - - As an alternative to using Spring's - HibernateTemplate to implement DAOs, data access code - can also be written in a more traditional fashion, without wrapping the - Hibernate access code in a callback, while still respecting and - participating in Spring's generic DataAccessException - hierarchy. The HibernateDaoSupport base class offers - methods to access the current transactional Session - and to convert exceptions in such a scenario; similar methods are also - available as static helpers on the - SessionFactoryUtils class. Note that such code will - usually pass 'false' as the value of the - DoGetSession(..) method's - 'allowCreate' argument, to enforce running within a - transaction (which avoids the need to close the returned - Session, as its lifecycle is managed by the - transaction). Asking for the - - public class HibernateProductDao : HibernateDaoSupport, IProductDao { - - public Customer SaveOrUpdate(Customer customer) - { - ISession session = DoGetSession(false); - session.SaveOrUpdate(customer); - return customer; - } - } -} - - This code will not translate the Hibernate - exception to a generic DataAccessException. + 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. +
- Implementing DAOs based on plain Hibernate 1.2/2.0 API + 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 @@ -718,89 +591,156 @@ public class HibernateCustomerDao : ICustomerDao {
-
- Programmatic transaction demarcation +
+ The <literal>HibernateTemplate</literal> for Hibernate + 1.2 - 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. + The basic programming model for templating looks as follows for + methods that can be part of any custom data access object or business + service. There are no restrictions on the implementation of the + surrounding object at all, it just needs to provide a Hibernate + SessionFactory. It can get the latter from anywhere, + but preferably as an object reference from a Spring IoC container - via + a simple SessionFactory property setter. The + following snippets show a DAO definition in a Spring container, + referencing the above defined SessionFactory, and an + example for a DAO method implementation. <objects> - <object id="TransactionManager" - type="Spring.Data.NHibernate.HibernateTransactionManager, Spring.Data.NHibernate"> - - <property name="DbProvider" ref="DbProvider"/> + <object id="CustomerDao" type="Spring.Northwind.Dao.NHibernate.HibernateCustomerDao, Spring.Northwind.Dao.NHibernate"> <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; + public class HibernateCustomerDao : ICustomerDao { - private IProductDao productDao; + private HibernateTemplate hibernateTemplate; - private ICustomerDao customerDao; + public ISessionFactory SessionFactory + { + set { hibernateTemplate = new HibernateTemplate(value); } + } - private IOrderDao orderDao; + public Customer SaveOrUpdate(Customer customer) + { + hibernateTemplate.SaveOrUpdate(customer); + return customer; + } +} - private IShippingService shippingService; + The HibernateTemplate class provides many + methods that mirror the methods exposed on the Hibernate + Session interface, in addition to a number of + convenience methods such as the one shown above. If you need access to + the Session to invoke methods that are not exposed on + the HibernateTemplate, you can always drop down to a + callback-based approach like so. + public class HibernateCustomerDao : ICustomerDao { - public TransactionManager TransactionManager + private HibernateTemplate hibernateTemplate; + + public ISessionFactory SessionFactory + { + set { hibernateTemplate = new HibernateTemplate(value); } + } + + public Customer SaveOrUpdate(Customer customer) + { + return HibernateTemplate.Execute( + delegate(ISession session) + { + // do whatever you want with the session.... + session.SaveOrUpdate(customer); + return customer; + }) as Customer; + } + +} + + Using the anonymous delegate is particularly convenient when you + would otherwise be passing various method parameter calls to the + interface based version of this callback. Furthermore, when using + generics, you can avoid the typecast and write code like the + following + + IList<Supplier> suppliers = HibernateTemplate.ExecuteFind<Supplier>( + delegate(ISession session) + { + return session.CreateQuery("from Supplier s were s.Code = ?") + .SetParameter(0, code) + .List<Supplier>(); + }); + + where code is a variable in the surrounding block, accessible + inside the anonymous delegate implementation. + + A callback implementation effectively can be used for any + Hibernate data access. HibernateTemplate will ensure + that Session instances are properly opened and + closed, and automatically participate in transactions. The template + instances are thread-safe and reusable, they can thus be kept as + instance variables of the surrounding class. For simple single step + actions like a single Find, Load, SaveOrUpdate, or Delete call, + HibernateTemplate offers alternative convenience + methods that can replace such one line callback implementations. + Furthermore, Spring provides a convenient + HibernateDaoSupport base class that provides a + SessionFactory property for receiving a + SessionFactory and for use by subclasses. In + combination, this allows for very simple DAO implementations for typical + requirements: + + public class HibernateCustomerDao : HibernateDaoSupport, ICustomerDao +{ + public Customer SaveOrUpdate(Customer customer) { - 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; - }); + HibernateTemplate.SaveOrUpdate(customer); + return customer; } }
+
+ Implementing Spring-based DAOs without HibernateTemplate in + Hibernate 1.2 + + As an alternative to using Spring's + HibernateTemplate to implement DAOs, data access code + can also be written in a more traditional fashion, without wrapping the + Hibernate access code in a callback, while still respecting and + participating in Spring's generic DataAccessException + hierarchy. The HibernateDaoSupport base class offers + methods to access the current transactional Session + and to convert exceptions in such a scenario; similar methods are also + available as static helpers on the + SessionFactoryUtils class. Note that such code will + usually pass 'false' as the value of the + DoGetSession(..) method's + 'allowCreate' argument, to enforce running within a + transaction (which avoids the need to close the returned + Session, as its lifecycle is managed by the + transaction). Asking for the + + public class HibernateProductDao : HibernateDaoSupport, IProductDao { + + public Customer SaveOrUpdate(Customer customer) + { + ISession session = DoGetSession(false); + session.SaveOrUpdate(customer); + return customer; + } + } +} + + This code will not translate the Hibernate + exception to a generic DataAccessException. +
+
Declarative transaction demarcation @@ -926,6 +866,89 @@ public class HibernateCustomerDao : ICustomerDao { configuration of other features, such as rollback rules.
+
+ 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; + }); + } +} +
+
Transaction management strategies @@ -1035,9 +1058,10 @@ public class HibernateCustomerDao : ICustomerDao { ... do multiple operations with a single session, possibly in multiple transactions. } - 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 + 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.
diff --git a/src/Spring/Spring.Data.NHibernate20/Data/NHibernate/LocalSessionFactoryObject.cs b/src/Spring/Spring.Data.NHibernate20/Data/NHibernate/LocalSessionFactoryObject.cs index acf94671..8a6171d4 100644 --- a/src/Spring/Spring.Data.NHibernate20/Data/NHibernate/LocalSessionFactoryObject.cs +++ b/src/Spring/Spring.Data.NHibernate20/Data/NHibernate/LocalSessionFactoryObject.cs @@ -88,10 +88,6 @@ namespace Spring.Data.NHibernate private string[] configFilenames; - /// - /// TODO: consider changing to NamevalueCollection for easier - /// cut-n-paste from existing App.config based configurations. - /// private IDictionary hibernateProperties; private IDbProvider dbProvider; diff --git a/src/Spring/Spring.Data.NHibernate21/Data/NHibernate/Bytecode/BytecodeProvider.cs b/src/Spring/Spring.Data.NHibernate21/Data/NHibernate/Bytecode/BytecodeProvider.cs index 6de27b0c..7f69543e 100644 --- a/src/Spring/Spring.Data.NHibernate21/Data/NHibernate/Bytecode/BytecodeProvider.cs +++ b/src/Spring/Spring.Data.NHibernate21/Data/NHibernate/Bytecode/BytecodeProvider.cs @@ -33,7 +33,7 @@ using Spring.Objects.Factory; namespace Spring.Data.NHibernate.Bytecode { /// - /// + /// Bytecode provider using Spring Proxy /// /// Fabio Maulo public class BytecodeProvider : IBytecodeProvider