I am quite a newbie using NHibernate, but I am pretty sure that there is an error in the implementation of BasicCollectionPersister and/or AbstractCollectionPersister.
I was trying to use the <idbag> mapping, with no success. This is the mapping:
Code:
<idbag name="Preferencias" table="PREFERENCIA_USUARIO">
<collection-id column="ID_PREFERENCIA_USUARIO" type="Int32">
<generator class="identity"/>
</collection-id>
<key column="ID_USUARIO" />
<many-to-many
class="Sky.Enterprise.VO.Entity.PreferenciaVO, Sky.Enterprise.VO"
column="ID_PREFERENCIA"
/>
</idbag>
And the following error was occurring:
Code:
System.InvalidCastException occurred
Message="Failed to convert parameter value from a Object to a Int32."
Source="System.Data"
StackTrace:
at System.Data.SqlClient.SqlParameter.CoerceValue(Object value, MetaType destinationType)
at System.Data.SqlClient.SqlParameter.GetCoercedValue()
at System.Data.SqlClient.SqlParameter.Validate(Int32 index)
at System.Data.SqlClient.SqlCommand.BuildParamList(TdsParser parser, SqlParameterCollection parameters)
at System.Data.SqlClient.SqlCommand.BuildExecuteSql(CommandBehavior behavior, String commandText, SqlParameterCollection parameters, _SqlRPC& rpc)
at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result)
at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(DbAsyncResult result, String methodName, Boolean sendToPipe)
at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
at NHibernate.Impl.BatcherImpl.ExecuteNonQuery(IDbCommand cmd) in C:\\NHibernate\1.2.0.alpha1\Src\Main\Impl\BatcherImpl.cs:line 208
After some debugging, I understood what was happening: NHibernate was trying to assign a value to the field PREFERENCIA_USUARIO.ID_PREFERENCIA_USUARIO, which is an IDENTITY Sql Server field.
The value being assigned was NHibernate.Id.IdentityGenerator.
It seems that AbstractCollectionPersister and BasicCollectionPersister are not dealing correctly with IDENTITY PK's (unlike SingleTableEntityPersister, which correctly generates an insert without the IDENTITY field).
I have made the following changes, to allow the insertion of the <idbag> mapping:
- NHibernate.Persister.Collection.BasicCollectionPersister.GenerateInsertRowString methodReplaced
Code:
if (hasIdentifier)
with
Code:
if (hasIdentifier && !(IdentifierGenerator is NHibernate.Id.IdentityGenerator))
- NHibernate.Persister.Collection.AbstractCollectionPersister.Recreate method
Same as above.
These changes seemed to work, but I cannot tell for sure that it is THE right way to do it...
Any comments? :-)