PDA

View Full Version : Exception on HibernateTemplate.SaveOrUpdate



tborowski
05-22-2007, 03:51 PM
Hi,

I recently changed my datasource over from MS Access to SQLExpress 2005. After the change, when trying to perform a HibernateTemplate.SaveOrUpdate() operation I am getting a strange error and I cannot figure out why. The error I am getting is:

"'Errors' node cannot be resolved for the specified root context."

I am using Spring.Data.NHibernate nightly build 20070204-2142.

Here is the code that calls the HibernateTemplate method:


public override Boolean Save(AttachmentXRef ai)
{
Boolean success = false;

try
{
attachTransUtil.GetTransactionChangeType(ai.Attach ment);
HibernateTemplate.SaveOrUpdate(ai.Attachment);

attachTransUtil.GetTransactionChangeType(ai);
HibernateTemplate.SaveOrUpdate((AttachmentImports) ai);

success = true;
}
catch (Exception e)
{
log.Error(e);
}

Here is my Spring-Config.xml:


<db:dbProvider id="DbProvider"
provider="SqlServer-2.0"
connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirector y|\MARS.mdf;User ID=user;Password=password;Integrated Security=True"/>


<object id="SessionFactory" type="Spring.Data.NHibernate.LocalSessionFactoryObject, Spring.Data.NHibernate" singleton="true">
<property name="DbProvider" ref="DbProvider" />
<property name="MappingAssemblies">
<list>
<value>DPMCore</value>
</list>
</property>
<property name="HibernateProperties">
<dictionary>
<entry key="hibernate.connection.provider" value="NHibernate.Connection.DriverConnectionProvider" />
<!--<entry key="hibernate.show_sql" value="true" />-->
<!--<entry key="hibernate.hbm2ddl.auto" value="create" />-->

<!-- SQL Server Express DB -->
<entry key="hibernate.dialect" value="NHibernate.Dialect.MsSql2000Dialect" />
<!--
<entry key="hibernate.connection.driver_class" value="NHibernate.Driver.SqlClientDriver" />
<entry key="hibernate.connection.connection_string" value="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirector y|\MARS.mdf;User ID=MARS_USER;Password=mar$User!;Integrated Security=True" />
-->

</dictionary>
</property>
</object>

I know specifically why the exception is being thrown. The reason is that some of the date properties in the Attachment object are not being set and SQL server is throwing a SqlDateTime overflow exception, but the AdoExceptionTranslator seems to be failing thus giving me the error described above.

Here is the stacktrace:

Spring.Objects.InvalidPropertyException was caught
Message="'Errors' node cannot be resolved for the specified root context."
Source="Spring.Core"
OffendingPropertyName="Errors"
StackTrace:
at Spring.Expressions.PropertyOrFieldNode.InitializeN ode(Object context)
at Spring.Expressions.PropertyOrFieldNode.Get(Object context, IDictionary variables)
at Spring.Expressions.BaseNode.GetValue(Object context, IDictionary variables)
at Spring.Expressions.Expression.Get(Object context, IDictionary variables)
at Spring.Expressions.BaseNode.GetValue(Object context, IDictionary variables)
at Spring.Expressions.ExpressionEvaluator.GetValue(Ob ject root, String expression)
at Spring.Data.Common.DbProvider.ExtractError(Excepti on e)
at Spring.Data.Support.ErrorCodeExceptionTranslator.E xtractErrorCode(Exception exception)
at Spring.Data.Support.ErrorCodeExceptionTranslator.T ranslate(String task, String sql, Exception exception)
at Spring.Data.NHibernate.HibernateAccessor.ConvertAd oAccessException(ADOException ex)
at Spring.Data.NHibernate.HibernateTemplate.Execute(I HibernateCallback action, Boolean exposeNativeSession)
at Spring.Data.NHibernate.HibernateTemplate.SaveOrUpd ate(Object entity)
at gov.usda.mars.dpm.dao.imports.ImportAttachmentDAO. Save(AttachmentXRef ai) in C:\projects\VS2005\DPSCore\DPSCore\dao\imports\Imp ortAttachmentDAO.cs:line 75


Any help would be appreciated.

Thanks!

Mark Pollack
05-22-2007, 08:11 PM
Hi,
It looks like the inner exception of NHibernate's ADOException isn't of the type SqlException, so the Errors property is not present. It is hard to tell what exactly is the inner exception inside NHibernate's ADOException in this case. Is it possible for you to load add the Spring.Data.NHibernate project into your solution and set a breakpoint in the method ConvertAdoAccessException. (Big favor :).) I can also try to reproduce it you specify the exact mismatch that is happening between the object and the table.

The issue does bring to light a few improvements that can be done to make the conversion process more robust. I'll make those changes. Any chance you can update to the latest version when those changes are made?

In the meantime, you can change the expression that is in the dbproviders.xml for the object id=SqlServer-2.0, constructor-arg name =
errorCodeExceptionExpression to the following



#this.GetType().IsAssignableFrom(T(System.Data.Sql Client.SqlException)) ? Errors[0].Number.ToString() : 'noerrorstring'


either by editing dbproviders.xml by hand, or you can register a new provider, with just this change, as described in the docs.

Changing the expression to the above should help in most cases. If not set errorCodeExpressionException to a constant value, i.e. 'noerrorstring', and you will get past this internal exception, but every data related exception thrown will be of the type Spring.Data.UncategorizedAdoException.

Cheers,
Mark

tborowski
05-22-2007, 10:30 PM
Mark,

Thanks for getting back to me so quickly.

So I added the Spring.Data.NHibernate project to my project and set the breakpoint at the method ConvertAdoAccessException.

Here is the exception:

could not insert: [gov.usda.mars.dpm.data.core.Attachment#2]

and here is the inner exception:

SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM.

And is a System.Data.SqlTypes.SqlTypeException.

This makes sense since when I created a new Attachment object I did not set any of the properties that were of type DateTime. And on the initial creation of the DateTime type properties, I noticed C# defaults their values to 1/1/0001 12:00:00 AM. So obviously I should either have those property types instantiate to a null value or just make sure that all of the DateTime properties are set before calling SaveOrUpdate.

I have not gotten a chance to edit the dbproviders.xml yet, but as soon as I have had a chance to test it out I will let you know.

Thanks again,
Tony

Mark Pollack
05-23-2007, 06:30 AM
Hi,
This change, which is now in the code base, more directly addresses the bug you found. In HibernateTemplate, in the Execute methods, i.e. line ~858, the catch block should be



catch (ADOException ex)
{
IDbProvider dbProvider = SessionFactoryUtils.GetDbProvider(SessionFactory);
if (dbProvider != null && dbProvider.IsDataAccessException(ex.InnerException ))
{
throw ConvertAdoAccessException(ex);
}
else
{
// Callback code throw application exception or other non DB related exception.
throw;
}
}


Since you have the solution already imported, you can make this change directly, or download the latest build.

Cheers,
Mark

tborowski
05-23-2007, 04:01 PM
Mark,

I made the code changes to the solution and I was able to catch the exception with the inner exception.

Thanks so much for your help!

Tony