View Full Version : Spring.net + NHibernate , no CurrentSessionContext configured
kenghaochen
06-15-2007, 03:55 AM
I use Spring.net 1.1 and NHibernate 1.2, but when I query via NHiberante, following exception occured
No CurrentSessionContext configured (set the property hibernate.current_session_
context_class)!
NHibernate.HibernateException: No CurrentSessionContext configured (set the prop
erty hibernate.current_session_context_class)!
於 NHibernate.Impl.SessionFactoryImpl.GetCurrentSessi on()
於 SpringConTest.CUDAO.findAll() 於 C:\code\VB2005\SpringConTest\SpringConTes
t\CUDAO.vb: 行 16
於 SpringConTest.Module1.Main() 於 C:\code\VB2005\SpringConTest\SpringConTest
\Module1.vb: 行 16
and My config like follow
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns='http://www.springframework.net'>
<object id="cu" type="SpringConTest.CU,SpringConTest">
<property name="name" value="Michael Chen"/>
</object>
<object id="MySessionFactory" type="Spring.Data.NHibernate.LocalSessionFactoryObject,S pring.Data.NHibernate12">
<property name="DbProvider" ref="DbProvider"/>
<property name="MappingAssemblies">
<list>
<value>SpringConTest</value>
</list>
</property>
<property name="HibernateProperties">
<dictionary>
<entry key="hibernate.connection.provider"
value="NHibernate.Connection.DriverConnectionProvider"/>
<entry key="hibernate.dialect"
value="NHibernate.Dialect.MsSql2005Dialect"/>
<entry key="hibernate.connection.driver_class"
value="NHibernate.Driver.SqlClientDriver"/>
<entry key="hibernate.current_session_context_class"
value="thread"/>
</dictionary>
</property>
</object>
<object id="CUDAO" type="SpringConTest.CUDAO,SpringConTest">
<property name="SessionFactory" ref="MySessionFactory"/>
</object>
</objects>
How can I resolve this problem ?
Mark Pollack
06-15-2007, 05:01 PM
Hi,
In your configuration your are specifying the value of 'thread' for the property hibernate.current_session_context_class. This is not a supported value, you should probably see an error message from NHibernate in your log saying 'Unable to construct current session context [thread]'.
Out-of-the-box NHibernate provides an implementation of the ICurrentSessionContext interface which can be used in a web environment and is refered to via the name 'managed_web'. Read the NHibernate docs on this (http://www.hibernate.org/hib_docs/nhibernate/1.2/reference/en/html/architecture.html#architecture-current-session) for more informaiton.
Spring provides an implementation of ICurrentSessionContext that you can use. This will let you use the plain NHibernate 1.2 API in your data access code and participate in Spring's transaction management functionality, in this case you would use a HibernateTransactionManager. You can configure this 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. If you use Spring's HibernateTransactionManager then one session is created for the transaction and bound the thread local storage, which is what will be returned by calls to ISessionFactory.GetCurrentSession()
Cheers,
Mark
Apo007
06-27-2007, 10:39 AM
Hi!
I have the same problem but I don't really understand what you mean... I try this in my DAO.xml:
<object id="sessionFactory" type="Spring.Data.NHibernate.LocalSessionFactoryObject, Spring.Data.NHibernate12">
<property name="DbProvider" ref="dbProvider"/>
<!--<property name="ExposeTransactionAwareSessionFactory" value="true"/>-->
<property name="MappingAssemblies">
<list>
<value>ApoNHSTest.BLL.Domain</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"/>
<!--<entry key="hibernate.current_session_context_class"
value="managed_web"/>-->
</dictionary>
</property>
</object>
<object id="HibernateTransactionManager"
type="Spring.Data.NHibernate.HibernateTransactionManager , Spring.Data.NHibernate12">
<property name="DbProvider" ref="dbProvider"/>
<property name="SessionFactory" ref="sessionFactory"/>
</object>
<object id="clientDAO" type="ApoNHSTest.DAL.DAO.ClientDAO, ApoNHSTest.DAL">
<property name="sessionFactory" ref="sessionFactory"/>
</object>
and this is my Services.xml:
<object id="clientServices" type="ApoNHSTest.BLL.Services.ClientServices, ApoNHSTest.BLL.Services">
<property name="clientDAO" ref="clientDAO"/>
</object>
<object id="TxProxyConfigurationTemplate" abstract="true"
type="Spring.Transaction.Interceptor.TransactionProxyFac toryObject, Spring.Data">
<property name="PlatformTransactionManager" ref="HibernateTransactionManager"/>
<!--<property name="Target" ref="clientServices"/>-->
<property name="TransactionAttributes">
<name-values>
<!-- Add common methods across your services here -->
<add key="Get*" value="PROPAGATION_REQUIRED"/>
</name-values>
</property>
</object>
<object id="clientServicesUsingTxPFO" parent="TxProxyConfigurationTemplate">
<property name="Target" ref="clientServices"/>
</object>
When I use <property name="ExposeTransactionAwareSessionFactory" value="true"/> and I call in my Main()
IClientServices clientServices = ctx["clientServices"] as IClientServices;
clientServices.GetClient(1);
I get "Process is terminated due to StackOverflowException." with the ExposeTransactionAwareSessionFactory property.
I use DAO based on plain NHibernate API. I know that NHibernate 1.2 just supports managed_web and that Spring.NET offer an additionnal implementation of the current_session_context_class but I don't know its name (thread is for Hibernate...) or how to plug it correctly.
Thanks for the help !
Mark Pollack
06-27-2007, 03:16 PM
Hi,
How embarassing, I made a recursive call when setting the property ExposeTransactionAwareSessionFactory. This fix is in CVS now, I'll trigger a build so you can download an updated dll. Mor e importantly, I'll update the docs (currenlty Sec 19.2.5 (http://www.springframework.net/doc-1.1-M1/reference/html/orm.html#orm-hibernate-straight)) to show the specific configuration XML for this case. The general idea is what you did, i.e. you should set either ExposeTransactionAwareSessionFactory to true on LocalSessionFactoryObject, which is equivalent to registering the key
<entry key="hibernate.current_session_context_class"
value="Spring.Data.NHibernate.SpringSessionContext, Spring.Data.NHibernate"/>
within HibernateProperties.
Let me know if you run into any more issues with this approach, I'll update one of the example apps to use this functionality.
Cheers,
Mark
Apo007
06-27-2007, 03:36 PM
Thanks for the answer !
I try
<object id="sessionFactory" type="Spring.Data.NHibernate.LocalSessionFactoryObject, Spring.Data.NHibernate12">
<property name="DbProvider" ref="dbProvider"/>
<!--<property name="exposeTransactionAwareSessionFactory" value="true" />-->
<property name="MappingAssemblies">
<list>
<value>ApoNHSTest.BLL.Domain</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"/>
<entry key="hibernate.current_session_context_class"
value="Spring.Data.NHibernate.SpringSessionContext, Spring.Data.NHibernate"/>
</dictionary>
</property>
</object>
but I get :Exception non gérée : NHibernate.HibernateException: No CurrentSessionContext configured (set the property hibernate.current_session_context_class)!
I try with
<entry key="hibernate.current_session_context_class" value="Spring.Data.NHibernate.SpringSessionContext, Spring.Data.NHibernate12"/>
and finally I get
Exception non gérée : NHibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
Thanks
Mark Pollack
06-27-2007, 03:54 PM
Hi,
Yes, that class is only in the assembly Spring.Data.NHibernate12 (it is a 1.2 feature), my bad. I'll investigate more and get back to you shortly. Thanks for reporting the issue.
Mark
Apo007
06-27-2007, 04:33 PM
OK and thanks for all!
Spring.NET rocks!
Mark Pollack
06-27-2007, 05:18 PM
Hi,
You seemed to indicate in your previous email that there was still an error even after you registered the current_session_context_class from the correct spring namespace. Is that still the case? In my tests I didn't encounter this so it maybe something else if you are experiencing an error.
The DAO code should be accessing the current session like so,
public void Create(TestObject to)
{
SessionFactory.GetCurrentSession().Save(to);
}
and have some transactional advice around that method, say at the service layer.
Cheers,
Mark
Apo007
06-28-2007, 11:27 AM
Hi !
Yes, sorry, you must be right !
I've just testing it whith the TransactionAtribute and a DeclarativeServicesAttributeDriven.xml, it's working great! (I need to use the sessionFactory.GetCurrentSession().Get() instead of Load because the proxy can't be initialize: it depends on the architecture, doesn't it ?)
But if I try a DeclarativeServicesTxProxyFactoryDriven.xml I get the issue I wrote before. Could you just take a look at my services.xml file from my previous post, please ?
I thought we could use two possiblities to weave advices to the code (I tried AspectDNG) by using :
-attributes
-xml weaving mode through:
<property name="TransactionAttributes">
<name-values>
<!-- Add common methods across your services here -->
<add key="Get*" value="PROPAGATION_REQUIRED"/>
</name-values>
</property>
My ClientDAO.cs looks like:
public class ClientDAO : IClientDAO {
private ISessionFactory sessionFactory;
public ISessionFactory SessionFactory {
get { return sessionFactory; }
set { sessionFactory = value; }
}
public Client SelectById(int id) {
return sessionFactory.GetCurrentSession().Get<Client>(id);
}
...
}
and my ClientServices.cs
//using Spring.Transaction.Interceptor;
...
public class ClientServices : IClientServices {
private IClientDAO clientDAO;
public IClientDAO ClientDAO {
get { return clientDAO; }
set { clientDAO = value; }
}
//[Transaction(ReadOnly = false)]
public Client GetClient(int id) {
return clientDAO.SelectById(id);
}
...
}
Thank you for the time and effort you have devoted to look on my problem!
Apo007
06-28-2007, 01:56 PM
I solved my problem, I didn't use the proxy but the clientServices
IClientServices clientServices = ctx["clientServices"] as IClientServices;
instead of
IClientServices clientServices = ctx["clientServicesUsingTxPFO"] as IClientServices;
Sorry
Mark Pollack
06-28-2007, 03:39 PM
Hi,
Glad you are on the right path now. You can avoid getting a reference to the unadvised object by declaring it as an inner-object, i.e,
<object id="clientServicesUsingTxPFO" parent="TxProxyConfigurationTemplate">
<property name="Target">
<object type="ApoNHSTest.BLL.Services.ClientServices, ApoNHSTest.BLL.Services">
<property name="clientDAO" ref="clientDAO"/>
</object>
</property>
</object>
In which case, it would be better to name the object simply 'clientServices' instead of the one with the UsingTxPFO suffice. The docs have some dicussion on this approach. (refs: 1 (http://www.springframework.net/doc-latest/reference/html/objects.html#objects-inline-object),2 (http://www.springframework.net/doc-latest/reference/html/transaction.html#tx-txproxyfactoryobject))
Cheers,
Mark
vBulletin® v3.7.3, Copyright ©2000-2008, Jelsoft Enterprises Ltd.