View Full Version : DataAccessException when using NHibernateTemplate
mysomic
01-16-2008, 11:20 PM
When I call a HibernateTemplate load method for a non-existing id I am getting a
NHibernate.ObjectNotFoundException
I thought that one of the advantages of using the Dao templates is the consistent spring exception hierarchy. Or am I doing something wrong.
Many thx.
Mark Pollack
01-17-2008, 03:19 PM
Hi,
You are certainly correct, that is one of the advantages (one of the few remaining if you are using NH 1.2). I'm not able to reproduce the behavior. I tried NH 1.0 and NH 1.2
Reviewing the Spring code looks correct, i.e. there is a catch in the Execute method for all HibernateExceptions and then a translation call to the DAO exception hierarchy. The Load method delegates to Execute.
In NH 1.0 my test shows
Spring.Data.NHibernate.HibernateObjectRetrievalFai lureException: No row with the given identifier exists: 2134324532, of class: Spring.Data.NHibernate.TestObject
However, in NH 1.2, you don't get an exception right away, but an empty proxy class. This is expected behavior, see here (http://forum.hibernate.org/viewtopic.php?t=965085). However, if you set lazy="true" in the mapping, then you get the same exception as above. Here is my full stack trace
Spring.Data.NHibernate.HibernateObjectRetrievalFai lureException: No row with the given identifier exists: 234, of class: DAL.TestObject
at Spring.Data.NHibernate.Generic.HibernateTemplate.E xecute[T](IHibernateCallback`1 action, Boolean exposeNativeSession) in HibernateTemplate.cs:line 1154 (cref://90F2D070-6F98-4926-A626-BD7A6071D6D9/d:Data/d:NHibernate/d:Generic/f:HibernateTemplate.cs*1154*1)
at Spring.Data.NHibernate.Generic.HibernateTemplate.L oad[T](Object id, LockMode lockMode) in HibernateTemplate.cs:line 671 (cref://90F2D070-6F98-4926-A626-BD7A6071D6D9/d:Data/d:NHibernate/d:Generic/f:HibernateTemplate.cs*671*1)
at Spring.Data.NHibernate.Generic.HibernateTemplate.L oad[T](Object id) in HibernateTemplate.cs:line 655 (cref://90F2D070-6F98-4926-A626-BD7A6071D6D9/d:Data/d:NHibernate/d:Generic/f:HibernateTemplate.cs*655*1)
at DAL.NHibernateObjectDomainDAO`2.FindById(idT id) in NHibernateObjectDomainDAO.cs:line 44 (cref://C381020F-8AEF-4607-9E60-999D1C30B1AD/f:NHibernateObjectDomainDAO.cs*44*1)
at DAL.SimpleService.DoWork(TestObject to) in SimpleService.cs:line 46 (cref://C381020F-8AEF-4607-9E60-999D1C30B1AD/f:SimpleService.cs*46*1)
at Spring.DynamicReflection.Method_DoWork_2164ba36a90 d43b18c08c28b7559c9a3.Invoke(Object target, Object[] args)
at Spring.Reflection.Dynamic.SafeMethod.Invoke(Object target, Object[] arguments) in DynamicMethod.cs:line 108 (cref://710961A3-0DF4-49E4-A26E-F5B9C044AC84/d:Reflection/d:Dynamic/f:DynamicMethod.cs*108*1)
at Spring.Aop.Framework.DynamicMethodInvocation.Invok eJoinpoint() in DynamicMethodInvocation.cs:line 89 (cref://3A3A4E65-45A6-4B20-B460-0BEDC302C02C/d:Aop/d:Framework/f:DynamicMethodInvocation.cs*89*1)
at Spring.Aop.Framework.AbstractMethodInvocation.Proc eed() in AbstractMethodInvocation.cs:line 257 (cref://3A3A4E65-45A6-4B20-B460-0BEDC302C02C/d:Aop/d:Framework/f:AbstractMethodInvocation.cs*257*1)
at Spring.Transaction.Interceptor.TransactionIntercep tor.Invoke(IMethodInvocation invocation) in TransactionInterceptor.cs:line 80 (cref://AE00E5AB-C39A-436F-86D2-33BFE33E2E40/d:Transaction/d:Interceptor/f:TransactionInterceptor.cs*80*1)
at Spring.Aop.Framework.AbstractMethodInvocation.Proc eed() in AbstractMethodInvocation.cs:line 282 (cref://3A3A4E65-45A6-4B20-B460-0BEDC302C02C/d:Aop/d:Framework/f:AbstractMethodInvocation.cs*282*1)
at Spring.Aop.Framework.DynamicProxy.AdvisedProxy.Inv oke(Object proxy, Object target, Type targetType, MethodInfo targetMethod, Object[] args, IList interceptors) in AdvisedProxy.cs:line 222 (cref://3A3A4E65-45A6-4B20-B460-0BEDC302C02C/d:Aop/d:Framework/d:DynamicProxy/f:AdvisedProxy.cs*222*1)
at CompositionAopProxy_c3b56cd28402447e92f6162980d7f9 31.DoWork(TestObject to)
at DAL.Tests.DALTests.Test() in DALTests.cs:line 57 (cref://E03CE883-EBC2-45C7-B029-3ADFB822F1C7/f:DALTests.cs*57*1)
NHibernate.ObjectNotFoundException: No row with the given identifier exists: 234, of class: DAL.TestObject
at NHibernate.Impl.SessionImpl.Load(Type clazz, Object id)
at NHibernate.Impl.SessionImpl.Load[T](Object id)
at Spring.Data.NHibernate.Generic.LoadByTypeHibernate Callback`1.DoInHibernate(ISession session) in HibernateTemplate.cs:line 1408 (cref://90F2D070-6F98-4926-A626-BD7A6071D6D9/d:Data/d:NHibernate/d:Generic/f:HibernateTemplate.cs*1408*1)
at Spring.Data.NHibernate.Generic.HibernateTemplate.E xecute[T](IHibernateCallback`1 action, Boolean exposeNativeSession) in HibernateTemplate.cs:line 1135 (cref://90F2D070-6F98-4926-A626-BD7A6071D6D9/d:Data/d:NHibernate/d:Generic/f:HibernateTemplate.cs*1135*1)
The source code for the first element in the stack track is
catch (HibernateException ex)
{
throw ConvertHibernateAccessException(ex);
}
Can you wrap up a simple example reproducing the problem and post it? What versions (Spring, NH) are you using?
Cheers,
Mark
Mark Pollack
01-17-2008, 03:21 PM
Hi,
Just to add, the intention is to exception ObjectRetrievalFailureException, HibernateObjectRetrievalFailureException is a subclass.
Cheers,
Mark
mysomic
01-17-2008, 09:26 PM
Mark,
Many thanks - that was it! I have just recently upgraded to 1.2 and it was the proxy catching me out. That's a pretty big gotcha!
T entity = (T) HibernateTemplate.Load(typeof (T), id);
log.Debug("Found entity: " + entity);
Obviously now in hindsight, it was the logging line throwing the NHibernate exception rather than the HibernateTemplate.
What is the best way iyo to force the ObjectRetrievalFailure. Should I use get instead of load and throw it myself?
Tom
Mark Pollack
01-18-2008, 03:59 PM
Hi Tom,
Yes, you should use Get() and throw the exception yourself if the returned obect is null. That is the sure-fire way to force the test for existence in the DB. Maybe adding a utility method to your base DAO object would avoid this (minimal) code duplicaiton if it comes up often.
Cheers,
Mark
mysomic
01-18-2008, 08:51 PM
Hi Tom,
Yes, you should use Get() and throw the exception yourself if the returned obect is null. That is the sure-fire way to force the test for existence in the DB. Maybe adding a utility method to your base DAO object would avoid this (minimal) code duplicaiton if it comes up often.
Cheers,
Mark
Yes indeed, all of my DAOs inherit an abstract Load() so it's pretty trivial to refactor.
You're doing a fantastic job with spring.net + forum support - can't thank you enough.
Tom
mysomic
01-23-2008, 08:21 PM
Mark,
I wonder if you are still around on this topic as I do have another quite similar issue....
When calling the HibernateTemplate.Save() method from a unit test which I know to cause an underlying database foreign constraint to fail, I get back an NHibernate.ADOException.
Now I see that this exception is explicitly caught in spring source and a test performed - IsDataAccessException(ex.InnerException). If it fails the original exception is simply rethrown. In this case the inner exception is MySqlException.
All in all I would have hoped for DataIntegrityViolationException, but am so wet behind the ears that I don't entirely know what's going on here.
Mark Pollack
01-24-2008, 02:57 PM
Hi,
I would also expect that behavior. I'm wondering why the call
dbProvider.IsDataAccessException(ex.InnerException ) is not returning true. What MySql client library are you using? 1.0.doesn't inherit from DbException but that is an older library I believe. 5.0 and 5.1 do inherit from System.Data.Common.DbException.
In anycase, since we know it is something data access related (NHibernate.ADOException) we shouldn't rethrow that exception, but instead wrap it in HibernateSystemException (a subclass of UncategorizedDataAccessException). I'll make that change.
If you could dig a little into why the translation is not occuring, or post details of the inner exception, that would be a big help.
Cheers,
Mark
mysomic
01-24-2008, 11:23 PM
Yes, that was precisely the issue, an old MySql driver where that exception derived straight from System.Exception. I've swapped out drivers and am now getting a Spring.Data.UncategorizedAdoException.
I'm assuming that if I added the 1452 error number for an exception translation to DataIntegrityViolationException that it would not be portable, right?
Mark Pollack
01-25-2008, 12:30 AM
Hi,
Actually, now that I think of it, we should fallback to the ".NET 1.1 way" if the check for inheritance from System.Data.Common.DbException fails, though in your case you should update drivers anyway.
Yes, if 1452 isn't in there, you should add it and it will be mapped accordingly. Let me know if you think 1452 should be added to the default list. Here is a recent thread (http://forum.springframework.net/showthread.php?t=4247) with some more details on how to add your own error code.
Mark
Powered by vBulletin® Version 4.2.0 Copyright © 2013 vBulletin Solutions, Inc. All rights reserved.