These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 5 posts ] 
Author Message
 Post subject: Error: Object must implement IConvertible
PostPosted: Fri Sep 12, 2008 3:01 pm 
Newbie

Joined: Thu Sep 04, 2008 12:44 pm
Posts: 10
Hello,

I am getting the following error from when I am saving an object. I have cut out my own stack from the error message to..

Quote:
[InvalidCastException: Object must implement IConvertible.]
System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider) +2560525
System.Data.SqlClient.SqlParameter.CoerceValue(Object value, MetaType destinationType) +896

[InvalidCastException: Failed to convert parameter value from a Object to a Int32.]
System.Data.SqlClient.SqlParameter.CoerceValue(Object value, MetaType destinationType) +943
System.Data.SqlClient.SqlParameter.GetCoercedValue() +29
System.Data.SqlClient.SqlParameter.Validate(Int32 index, Boolean isCommandProc) +97
System.Data.SqlClient.SqlCommand.BuildParamList(TdsParser parser, SqlParameterCollection parameters) +166
System.Data.SqlClient.SqlCommand.BuildExecuteSql(CommandBehavior behavior, String commandText, SqlParameterCollection parameters, _SqlRPC& rpc) +253
System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async) +1005
System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result) +132
System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(DbAsyncResult result, String methodName, Boolean sendToPipe) +149
System.Data.SqlClient.SqlCommand.ExecuteNonQuery() +135
NHibernate.AdoNet.AbstractBatcher.ExecuteNonQuery(IDbCommand cmd) in D:\NHibernate\src\src\NHibernate\AdoNet\AbstractBatcher.cs:196
NHibernate.AdoNet.NonBatchingBatcher.AddToBatch(IExpectation expectation) in D:\NHibernate\src\src\NHibernate\AdoNet\NonBatchingBatcher.cs:39
NHibernate.Persister.Collection.BasicCollectionPersister.DoUpdateRows(Object id, IPersistentCollection collection, ISessionImplementor session) in D:\NHibernate\src\src\NHibernate\Persister\Collection\BasicCollectionPersister.cs:230
NHibernate.Persister.Collection.AbstractCollectionPersister.UpdateRows(IPersistentCollection collection, Object id, ISessionImplementor session) in D:\NHibernate\src\src\NHibernate\Persister\Collection\AbstractCollectionPersister.cs:1315
NHibernate.Action.CollectionUpdateAction.Execute() in D:\NHibernate\src\src\NHibernate\Action\CollectionUpdateAction.cs:55
NHibernate.Engine.ActionQueue.Execute(IExecutable executable) in D:\NHibernate\src\src\NHibernate\Engine\ActionQueue.cs:130
NHibernate.Engine.ActionQueue.ExecuteActions(IList list) in D:\NHibernate\src\src\NHibernate\Engine\ActionQueue.cs:113
NHibernate.Engine.ActionQueue.ExecuteActions() in D:\NHibernate\src\src\NHibernate\Engine\ActionQueue.cs:149
NHibernate.Event.Default.AbstractFlushingEventListener.PerformExecutions(IEventSource session) in D:\NHibernate\src\src\NHibernate\Event\Default\AbstractFlushingEventListener.cs:240
NHibernate.Event.Default.DefaultFlushEventListener.OnFlush(FlushEvent event) in D:\NHibernate\src\src\NHibernate\Event\Default\DefaultFlushEventListener.cs:19
NHibernate.Impl.SessionImpl.Flush() in D:\NHibernate\src\src\NHibernate\Impl\SessionImpl.cs:1187


When I look through the log files I see the following SQL

Quote:
2008-09-12 14:38:04,995 [4] DEBUG NHibernate.AdoNet.AbstractBatcher - Opened new IDbCommand, open IDbCommands: 1
2008-09-12 14:38:04,995 [4] DEBUG NHibernate.AdoNet.AbstractBatcher - Building an IDbCommand object for the SqlString: UPDATE OrganizationSetting SET SettingValue = ?, SettingId = ? WHERE Id = ?
2008-09-12 14:38:04,995 [4] DEBUG NHibernate.Type.StringType - binding 'Quote' to parameter: 0
2008-09-12 14:38:04,995 [4] DEBUG NHibernate.Type.Int32Type - binding '1' to parameter: 1
2008-09-12 14:38:04,995 [4] DEBUG NHibernate.Type.Int32Type - binding 'System.Object' to parameter: 2
2008-09-12 14:38:04,995 [4] DEBUG NHibernate.SQL - UPDATE OrganizationSetting SET SettingValue = @p0, SettingId = @p1 WHERE Id = @p2; @p0 = 'Quote', @p1 = '1', @p2 = 'System.Object'
2008-09-12 14:38:04,995 [4] DEBUG NHibernate.Connection.DriverConnectionProvider - Obtaining IDbConnection from Driver


The error here is occuring because we are binding the string value of System.Object to an integer field. Interestingly NHibernate sees that this is an integer based on this log statement:
Quote:
NHibernate.Type.Int32Type - binding 'System.Object' to parameter: 2


My mapping file is:

Code:
<class name="Cutter.Domain.Membership.Organization" table="Organization" lazy="true">
      <id name="Id" column="OrganizationId">
         <generator class="guid" />
      </id>
      <property name="Name" column="Name" type="String" length="50"/>
      <property name="IsInitalized" />
      <property name="DateCreated" type="DateTime" update="false"/>
      <component name="Phone" class="Cutter.PhoneNumber">
         <property name="Number" column="PhoneNumber"></property>
         <property name="AreaCode" column="AreaCode"/>
         <property name="Extension" column="Extension"/>
         <property name="CountryCode" column="CountryCode"/>
      </component>
      <component class="Cutter.Address" name="Address">
         <property name="AddressLine1"></property>
         <property name="AddressLine2"></property>
         <property name="City"></property>
         <property name="State"></property>
         <property name="PostalCode"></property>
      </component>

      <idbag name="PersistedSettings" table="OrganizationSetting" generic="true" lazy="false" inverse="false" cascade="save-update" >
         <collection-id column="Id" type="int" >
            <generator class="identity"/>
         </collection-id>
         <key  column="OrganizationId"  >
            <column not-null="false" name="OrganizationId" />
         </key>

         <composite-element class="Cutter.Domain.Membership.Setting, Cutter">            
            <property column="SettingValue" name="Value"/>
            <many-to-one class="Cutter.Domain.Membership.SettingDefinition"  column="SettingId" name="Definition" cascade="none"/>               
         </composite-element>
      </idbag>


What the code here is doing is building up an Organization and I'm creating new Setting objects. The SettingDefinition is a mutable persisted object which my code is pulling in so essentially we have:

Code:
Organization org=new Organization(){initilizers....};

SettingDefinition def=settingDao.GetSetting("MySetting");
org.Settings.Add(new Setting(def){Value="SomeValue"});

orgDao.SaveOrUpdate(org);



The confusing piece is that this works fine in my unit tests but in some production code is where it is failing which is essentially doign the same thing.

The other thing is this code is within a loop. I am creating many organizations, and the first three or four have no issues. Then it fails.

However, I don't understand why nHibernate would be pulling System.Object for the id of an element of an idBag. Any thoughts or ideas?


Thanks,
Josh


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 12, 2008 3:14 pm 
Newbie

Joined: Thu Sep 04, 2008 12:44 pm
Posts: 10
One more question I forgot to ask. Why is nhibernate issuing a second update of the collection? Since this is a new object it's inserting it then its going back and trying to update the value. Any ideas on this?


Top
 Profile  
 
 Post subject:
PostPosted: Sat Sep 13, 2008 11:47 am 
Newbie

Joined: Thu Sep 04, 2008 12:44 pm
Posts: 10
Ok one more piece of information. I took my unit test code and put in my application, and saw there was no error. So the question was what was different.

The unit test code was only adding a single new item to the idbag. As soon as modified the code to add multiple items, I was generating the conversion error.

I am fairly convinced now this is a bug with nHibernate; however, I am unable to recreate the issue in a simpler project. So I am guessing I am misusing nHibernate in a way that they have not protected against.

If anyone can help that would be great. If you need more information let me know what I can provide.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Sep 14, 2008 7:20 am 
Expert
Expert

Joined: Thu Dec 14, 2006 5:57 am
Posts: 1185
Location: Zurich, Switzerland
Hmm, I have no idea about the IConvertible problem, but I can help you with the insert+update. Have a look at the parent/child example in the documentation:

http://www.hibernate.org/hib_docs/nhibernate/1.2/reference/en/html/example-parentchild.html

In your case the association is owned by the "Organization" object (the parent) not the Setting object (the child). This results in an insert for the new child and an update for the association. You can change this behavior by setting the parent end to inverse and add a many-to-one to the child. Then the association is owned by the child and only one insert is issued. Here is some more information about the consequences:

http://simoes.org/docs/hibernate-2.1/155.html

_________________
--Wolfgang


Top
 Profile  
 
 Post subject:
PostPosted: Mon Sep 15, 2008 2:20 pm 
Newbie

Joined: Thu Sep 04, 2008 12:44 pm
Posts: 10
Actually my issue was because nHibernate 2.0 doesn't support identity or native stategies for IDBags.

This caused the IConvertible and it also was the cause for the object being updated. When you issue a flush in nHibernate it would go through and find which objects had changed. To do this it compares the objects against a snapshot of the object.

When dealing with an idBag the snapshot only contains a single element no matter how many elements are in the bag. It looks like this is because the identifier that was being generated by nHibernate is the same for all elements (since the persistance layer wasn't getting the autogened identity).

Because the snapshot only has a single element in it when you flush the session it resulted in n-1 items being marked as dirty (where n is the number of elements in the idBag).

The solution was very easy, use a different strategy for id generation. I feel dumb since the docs said idBag doesn't support native for 1.2; however, I assumed this meant it would work with identity.

There is a jira issue 1297 which is essentially what I was experiencing and it looks like it will be included in NH 2.1.

Thanks for the response;-)

Josh


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 5 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.