Deleting an entity with reference to self - nhibernate

I have a class for messages in a message thread. Each message has a reference to the root message of the thread:
<class name="Message">
...
<many-to-one name="Root" not-null="true"/>
</class>
<joined-subclass name="Comment" extends="Message">
...
</joined-subclass>
Now I want to delete a comment. This works fine for all but the root comments. Deleting a root comment, where the Root property points to the message itself, yields the following exception:
NHibernate.PropertyValueException : not-null property references a null or transient value
at NHibernate.Engine.Nullability.CheckNullability(Object[] values, IEntityPersister persister, Boolean isUpdate)
at NHibernate.Event.Default.DefaultDeleteEventListener.DeleteEntity(IEventSource session, Object entity, EntityEntry entityEntry, Boolean isCascadeDeleteEnabled, IEntityPersister persister, ISet transientEntities)
at NHibernate.Event.Default.DefaultDeleteEventListener.OnDelete(DeleteEvent event, ISet transientEntities)
at NHibernate.Impl.SessionImpl.FireDelete(DeleteEvent event)
at NHibernate.Impl.SessionImpl.Delete(Object obj)
This error appeared first when I upgraded from NHibernate 3.0 to 3.3. When I remove the not-null constraint, I get an SQL exception indicating that the respective column constraint was violated. Now I wonder why NHibernate actually tries to save a to be deleted entity. Does anyone have an idea how to deal with this?

not-null should be set to false, because, at least one of these entries will require it: the first "father".

Related

NHibernate throwing cast exceptions with components

I'm using NHibernate, I have a one to many relationship with a cascade on delete. Mappings below.
<class name="Photo" table="photos">
<id name="RoomId" column="room_id">
<generator class="guid"/>
</id>
// omitted for brevity
<component name="Data" class="PhotoData" lazy="true">
<property name="Mime" column="mime"/>
<property name="Data" column="data" length="2048000"/>
</component>
</class>
<class name="Room" table="rooms">
// omitted for brevity
<bag name="Photos" lazy="false" fetch="join" cascade="delete" inverse="true">
<key>
<column name="room_id"/>
</key>
<one-to-many class="Photo"/>
</bag>
</class>
When I attempt delete a room, I get the following exception
Unable to cast object of type 'System.Object' to type 'PhotoData'
If I remove the component from my photo mapping I can delete the room and all the photos without a problem.
Any suggestions?
UPDATE: As per comment from #nemesv
The stack trace is below, there is no inner exception.
at (Object , GetterCallback )
at NHibernate.Bytecode.Lightweight.AccessOptimizer.GetPropertyValues(Object target) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Bytecode\Lightweight\AccessOptimizer.cs:line 27
at NHibernate.Tuple.Component.PocoComponentTuplizer.GetPropertyValues(Object component) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Tuple\Component\PocoComponentTuplizer.cs:line 68
at NHibernate.Type.ComponentType.GetPropertyValues(Object component, ISessionImplementor session) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Type\ComponentType.cs:line 291
at NHibernate.Engine.ForeignKeys.Nullifier.NullifyTransientReferences(Object value, IType type) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Engine\ForeignKeys.cs:line 74
at NHibernate.Engine.ForeignKeys.Nullifier.NullifyTransientReferences(Object[] values, IType[] types) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Engine\ForeignKeys.cs:line 38
at NHibernate.Event.Default.DefaultDeleteEventListener.DeleteEntity(IEventSource session, Object entity, EntityEntry entityEntry, Boolean isCascadeDeleteEnabled, IEntityPersister persister, ISet transientEntities) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Event\Default\DefaultDeleteEventListener.cs:line 204
at NHibernate.Event.Default.DefaultDeleteEventListener.OnDelete(DeleteEvent event, ISet transientEntities) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Event\Default\DefaultDeleteEventListener.cs:line 111
at NHibernate.Impl.SessionImpl.FireDelete(DeleteEvent event, ISet transientEntities) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Impl\SessionImpl.cs:line 2478
at NHibernate.Impl.SessionImpl.Delete(String entityName, Object child, Boolean isCascadeDeleteEnabled, ISet transientEntities) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Impl\SessionImpl.cs:line 975
at NHibernate.Engine.CascadingAction.DeleteCascadingAction.Cascade(IEventSource session, Object child, String entityName, Object anything, Boolean isCascadeDeleteEnabled) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Engine\CascadingAction.cs:line 158
at NHibernate.Engine.Cascade.CascadeToOne(Object parent, Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Engine\Cascade.cs:line 216
at NHibernate.Engine.Cascade.CascadeAssociation(Object parent, Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Engine\Cascade.cs:line 181
at NHibernate.Engine.Cascade.CascadeProperty(Object parent, Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Engine\Cascade.cs:line 148
at NHibernate.Engine.Cascade.CascadeCollectionElements(Object parent, Object child, CollectionType collectionType, CascadeStyle style, IType elemType, Object anything, Boolean isCascadeDeleteEnabled) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Engine\Cascade.cs:line 240
at NHibernate.Engine.Cascade.CascadeCollection(Object parent, Object child, CascadeStyle style, Object anything, CollectionType type) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Engine\Cascade.cs:line 201
at NHibernate.Engine.Cascade.CascadeAssociation(Object parent, Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Engine\Cascade.cs:line 185
at NHibernate.Engine.Cascade.CascadeProperty(Object parent, Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Engine\Cascade.cs:line 148
at NHibernate.Engine.Cascade.CascadeOn(IEntityPersister persister, Object parent, Object anything) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Engine\Cascade.cs:line 126
at NHibernate.Event.Default.DefaultDeleteEventListener.CascadeBeforeDelete(IEventSource session, IEntityPersister persister, Object entity, EntityEntry entityEntry, ISet transientEntities) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Event\Default\DefaultDeleteEventListener.cs:line 253
at NHibernate.Event.Default.DefaultDeleteEventListener.DeleteEntity(IEventSource session, Object entity, EntityEntry entityEntry, Boolean isCascadeDeleteEnabled, IEntityPersister persister, ISet transientEntities) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Event\Default\DefaultDeleteEventListener.cs:line 202
at NHibernate.Event.Default.DefaultDeleteEventListener.OnDelete(DeleteEvent event, ISet transientEntities) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Event\Default\DefaultDeleteEventListener.cs:line 111
at NHibernate.Event.Default.DefaultDeleteEventListener.OnDelete(DeleteEvent event) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Event\Default\DefaultDeleteEventListener.cs:line 30
at NHibernate.Impl.SessionImpl.FireDelete(DeleteEvent event) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Impl\SessionImpl.cs:line 2465
at NHibernate.Impl.SessionImpl.Delete(Object obj) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Impl\SessionImpl.cs:line 508
at DataAccess.Respository`1.<>c__DisplayClass7.<Delete>b__6(ISession s) in D:\svn\flatsharespa\DataAccess\Respository.cs:line 4

ERROR: Spring.Objects.Factory.ObjectCreationException : Error creating object with name 'NHibernate SessionFactory' defined in 'assembly'

I get the following error when running any NUnit integration test
- Assembly setup complete -
Beginning Processing of Tests -
Test 'PXL.IntegrationTests.EventDaoTests.deleteEvent' failed: Spring.Objects.Factory.ObjectCreationException : Error creating object with name 'NHibernateSessionFactory' defined in 'assembly [PXL.Dao.NHibernate, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null], resource [PXL.Dao.NHibernate.Dao.Dao.xml] line 18' : Initialization of object failed : Association references unmapped class: PXL.Domain.TBEvent
----> NHibernate.MappingException : Association references unmapped class: PXL.Domain.TBEvent
at Spring.Objects.Factory.Support.AbstractAutowireCapableObjectFactory.InstantiateObject(String name, RootObjectDefinition definition, Object[] arguments, Boolean allowEagerCaching, Boolean suppressConfigure)
at Spring.Objects.Factory.Support.AbstractObjectFactory.CreateAndCacheSingletonInstance(String objectName, RootObjectDefinition objectDefinition, Object[] arguments)
at Spring.Objects.Factory.Support.AbstractObjectFactory.GetObjectInternal(String name, Type requiredType, Object[] arguments, Boolean suppressConfigure)
at Spring.Objects.Factory.Support.DefaultListableObjectFactory.GetObjectsOfType(Type type, Boolean includePrototypes, Boolean includeFactoryObjects)
at Spring.Objects.Factory.ObjectFactoryUtils.ObjectsOfTypeIncludingAncestors(IListableObjectFactory factory, Type type, Boolean includePrototypes, Boolean includeFactoryObjects)
at Spring.Dao.Support.PersistenceExceptionTranslationInterceptor.DetectPersistenceExceptionTranslators(IListableObjectFactory objectFactory)
at Spring.Dao.Attributes.PersistenceExceptionTranslationPostProcessor.set_ObjectFactory(IObjectFactory value)
at Spring.Objects.Factory.Support.AbstractAutowireCapableObjectFactory.ConfigureObject(String name, RootObjectDefinition definition, IObjectWrapper wrapper)
at Spring.Objects.Factory.Support.AbstractAutowireCapableObjectFactory.InstantiateObject(String name, RootObjectDefinition definition, Object[] arguments, Boolean allowEagerCaching, Boolean suppressConfigure)
at Spring.Objects.Factory.Support.AbstractObjectFactory.CreateAndCacheSingletonInstance(String objectName, RootObjectDefinition objectDefinition, Object[] arguments)
at Spring.Objects.Factory.Support.AbstractObjectFactory.GetObjectInternal(String name, Type requiredType, Object[] arguments, Boolean suppressConfigure)
at Spring.Objects.Factory.Support.DefaultListableObjectFactory.GetObjectsOfType(Type type, Boolean includePrototypes, Boolean includeFactoryObjects)
at Spring.Context.Support.AbstractApplicationContext.RegisterObjectPostProcessors(IConfigurableListableObjectFactory objectFactory)
at Spring.Context.Support.AbstractApplicationContext.Refresh()
at Spring.Testing.NUnit.AbstractSpringContextTests.LoadContextLocations(String[] locations)
at Spring.Testing.NUnit.AbstractDependencyInjectionSpringContextTests.SetUp()
--MappingException
at NHibernate.Cfg.XmlHbmBinding.CollectionBinder.BindCollectionSecondPass(XmlNode node, Collection model, IDictionary`2 persistentClasses, IDictionary`2 inheritedMetas)
at NHibernate.Cfg.XmlHbmBinding.CollectionBinder.<>c__DisplayClassd.<AddCollectionSecondPass>b__c(IDictionary`2 persistentClasses)
at NHibernate.Cfg.Configuration.SecondPassCompile()
at Spring.Data.NHibernate.LocalSessionFactoryObject.AfterPropertiesSet()
at Spring.Objects.Factory.Support.AbstractAutowireCapableObjectFactory.InvokeInitMethods(Object target, String name, IConfigurableObjectDefinition definition)
at Spring.Objects.Factory.Support.AbstractAutowireCapableObjectFactory.ConfigureObject(String name, RootObjectDefinition definition, IObjectWrapper wrapper)
at Spring.Objects.Factory.Support.AbstractAutowireCapableObjectFactory.InstantiateObject(String name, RootObjectDefinition definition, Object[] arguments, Boolean allowEagerCaching, Boolean suppressConfigure)
Assembly TearDown
0 passed, 1 failed, 0 skipped, took 4.67 seconds (NUnit 2.5.5).
The line of code that the error refers to is the NHibernate Dao Configuration 1st line.
<!-- NHibernate Configuration -->
<object id="NHibernateSessionFactory" type="Spring.Data.NHibernate.LocalSessionFactoryObject, Spring.Data.NHibernate21" scope="application">
<property name="DbProvider" ref="DbProvider"/>
<property name="MappingAssemblies">
<list>
<value>PXL.Dao.NHibernate</value>
</list>
</property>
<property name="HibernateProperties">
<dictionary>
<entry key="hibernate.connection.provider" value="NHibernate.Connection.DriverConnectionProvider"/>
<entry key="dialect" value="NHibernate.Dialect.MsSql2008Dialect"/>
<entry key="connection.driver_class" value="NHibernate.Driver.SqlClientDriver"/>
</dictionary>
</property>
<!-- provides integation with Spring's declarative transaction management features -->
<property name="ExposeTransactionAwareSessionFactory" value="true" />
</object>
The missing file that it refers to "Association references unmapped class: PXL.Domain.TBEvent" does exist and as far as I can see there is nothing missing, the mapping file has no errors in it and there is a cs file for it to map to and all the interfaces exist and the row in the dao which refers to it also exists.
<object id="TBEventDao" type="PXL.Dao.NHibernate.HibernateTBEventDao, PXL.Dao.NHibernate">
<property name="SessionFactory" ref="NHibernateSessionFactory"/>
</object>
I know this is something simple, wonder if anyone here can give me some insight.
Make sure the Build Action of your mapping xml file is set to Embedded Resource and that the extension is .hmb.xml.

NHibernate gets crashed by a magic string

Here is my trivial program:
public class Entity
{
public virtual long Id { get; set; }
public virtual string Payload { get; set; }
}
class Program
{
static void Main( string[] args )
{
var config = new Configuration().Configure();
var sessionFactory = config.BuildSessionFactory();
using ( var session = sessionFactory.OpenSession() )
{
var entity = new Entity { Payload = "'))" };
session.Save( entity );
}
}
}
As long as Payload property is assigned any innocent string such as 'Hi there' everything works as expected. However this particular magic string ')) makes NHibernate throw an exception: 'Index was out of range. Must be non-negative and less than the size of the collection' when it tries to save the entity.
I wonder why NHibernate cares of the parameter content. It really shouldn't.
Or maybe something is very wrong with this sample?
NHibernate version is 2.1
SQL script:
create table tblEntity
(
EntityId BIGINT NOT NULL IDENTITY PRIMARY KEY
,Payload VARCHAR(10) NOT NULL
)
Mapping:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="MyNamespace.Entity, MyAssembly"
table="tblEntity">
<id name="Id" column="EntityId" unsaved-value="0">
<generator class="identity"/>
</id>
<property name="Payload"/>
</class>
</hibernate-mapping>
NHibernate settings:
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
<property name="connection.connection_string_name">Main</property>
<property name="connection.isolation">ReadCommitted</property>
<property name="default_schema">dbo</property>
<property name="format_sql">true</property>
<property name="query.substitutions">true=1;false=0</property>
<property name="proxyfactory.factory_class">NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu</property>
<mapping assembly="MyAssembly"/>
</session-factory>
</hibernate-configuration>
Nothing special as you can see, not too much room for mistakes.
Stack Trace
System.ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource)
System.ThrowHelper.ThrowArgumentOutOfRangeException()
System.Collections.Generic.List`1.get_Item(Int32 index)
NHibernate.AdoNet.Util.BasicFormatter.FormatProcess.CloseParen()
NHibernate.AdoNet.Util.BasicFormatter.FormatProcess.Perform()
NHibernate.AdoNet.Util.BasicFormatter.Format(String source)
NHibernate.AdoNet.Util.SqlStatementLogger.LogCommand(String message, IDbCommand command, FormatStyle style)
NHibernate.AdoNet.Util.SqlStatementLogger.LogCommand(IDbCommand command, FormatStyle style)
NHibernate.AdoNet.AbstractBatcher.LogCommand(IDbCommand command)
NHibernate.AdoNet.AbstractBatcher.Prepare(IDbCommand cmd)
NHibernate.AdoNet.AbstractBatcher.ExecuteReader(IDbCommand cmd)
NHibernate.Id.IdentityGenerator.InsertSelectDelegate.ExecuteAndExtract(IDbCommand insert, ISessionImplementor session)
NHibernate.Id.Insert.AbstractReturningDelegate.PerformInsert(SqlCommandInfo insertSQL, ISessionImplementor session, IBinder binder)
NHibernate.Persister.Entity.AbstractEntityPersister.Insert(Object[] fields, Boolean[] notNull, SqlCommandInfo sql, Object obj, ISessionImplementor session)
NHibernate.Persister.Entity.AbstractEntityPersister.Insert(Object[] fields, Object obj, ISessionImplementor session)
NHibernate.Action.EntityIdentityInsertAction.Execute()
NHibernate.Engine.ActionQueue.Execute(IExecutable executable)
NHibernate.Event.Default.AbstractSaveEventListener.PerformSaveOrReplicate(Object entity, EntityKey key, IEntityPersister persister, Boolean useIdentityColumn, Object anything, IEventSource source, Boolean requiresImmediateIdAccess)
NHibernate.Event.Default.AbstractSaveEventListener.PerformSave(Object entity, Object id, IEntityPersister persister, Boolean useIdentityColumn, Object anything, IEventSource source, Boolean requiresImmediateIdAccess)
NHibernate.Event.Default.AbstractSaveEventListener.SaveWithGeneratedId(Object entity, String entityName, Object anything, IEventSource source, Boolean requiresImmediateIdAccess)
NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.SaveWithGeneratedOrRequestedId(SaveOrUpdateEvent event)
NHibernate.Event.Default.DefaultSaveEventListener.SaveWithGeneratedOrRequestedId(SaveOrUpdateEvent event)
NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.EntityIsTransient(SaveOrUpdateEvent event)
NHibernate.Event.Default.DefaultSaveEventListener.PerformSaveOrUpdate(SaveOrUpdateEvent event)
NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.OnSaveOrUpdate(SaveOrUpdateEvent event)
NHibernate.Impl.SessionImpl.FireSave(SaveOrUpdateEvent event)
NHibernate.Impl.SessionImpl.Save(Object obj)
I have looked up the changes made to
src/NHibernate/AdoNet/Util/BasicFormatter.cs
there was an issue in NH 2.1 that caused this behavior, this was fixed in 2.1.1.GA.
Bugtracker: NH-1992
Changeset on github: Commit
I believe it might be a bug with NHibernate. When a command is logged (because you have show_sql set to true) it will write out your command and it will look something like this:
insert into tblEntity (Payload) VALUES(#p0); #p0 = ''(('
The logger then tries to tokenize the string and gets confused by the parentheses. Try submitting a bug to the NHibernate JIRA. In the meantime you can try turning off show_sql
I am not familiar with NHibernate, however what you are describing looks as if it might be the result of inadvertant SQL Injection Hopefully the linked wiki page might help.

Foreign Key Constraint is preventing NHibernate from saving child record

I have two tables:
SupportTicket
SupportTicketID
SupportTicketDate
SupportTicketNote
SupportTicketNoteID
SupportTicketNoteDate
SupportTicketID
With a foreign key constraint so I don't have any unassociated Notes...in sql that constraint is working properly.
On my SupportTicket class I have an IList SupportTicketNotes property and have it mapped as a bag (probably really should be a set but that's not important at the moment). The load works just fine. The problem is if I new up a SupportTicket, new up a SupportTicketNote, add the note to the ticket and save the ticket. NHibernate is inserting the SupportTicket, then inserting the SupportTicketNote with a SupportTicketID of zero which blows up of course because of the FK constraint. If I delete the constraint it will insert with the SupportTicketID of zero and then go back and do an update on the SupportTicketNote with the proper ID value...but that seems....wrong. Is there anything I might be doing in the mapping that is causing that?
UPDATED to include Many to One mapping on child object
Here's my current mapping for SupportTicket:
<bag name="_supportTicketNotes" table="SupportTicketNotes" access="field" cascade="save-update" inverse="true" >
<key column="SupportTicketID" foreign-key="FK_SupportTicketNotes_supporttickets" ></key>
<one-to-many class="NhibernateSample.DomainModel.SupportTicketNote, NhibernateSample.DomainModel" />
</bag>
Here is my mapping for SupportTicketNote (note my SupportTicketNote class has both the SupportTicketID and SupportTicket object properties):
<many-to-one name="SupportTicket" class="NhibernateSample.DomainModel.SupportTicket, NhibernateSample.DomainModel" column="SupportTicketId" cascade="all"/>
I haven't seen your full mapping, but the first thing that pops into my head is this section from the documentation:
Very Important Note: If the <key>
column of a <one-to-many> association
is declared NOT NULL, NHibernate may
cause constraint violations when it
creates or updates the association. To
prevent this problem, you must use a
bidirectional association with the
many valued end (the set or bag)
marked as inverse="true". See the
discussion of bidirectional
associations later in this chapter.
How have you mapped the parent SupportTicket property on SupportTicketNote? Are you setting the SupportTicket property when you add a SupportTicketNote to the collection? I almost always follow this pattern:
public class SupportTicket
{
private IEnumerable<SupportTicketNote> _notes = new List<SupportTicketNote>();
public IEnumerable<SupportTicketNote> Notes
{
get { return _notes; }
}
public void AddNote(SupportTicketNote note)
{
note.SupportTicket = this;
_notes.Add(note)
}
public void RemoveNote(SupportTicketNote note)
{
note.SupportTicket = null;
_notes.Remove(note)
}
}
Edited to add:
Your mapping for SupportTicketNote looks wrong. It should be many-to-one to SupportTicket and you shouldn't be mapping SupportTicketId at all. I've been using Fluent NHibernate for a while but I think the XML mapping should look like:
<many-to-one name="SupportTicket"
class="NhibernateSample.DomainModel.SupportTicket, NhibernateSample.DomainModel"
column="SupportTicketId" cascade="all"/>
You'll need to write your function in such a way that the persistance of the New SupportTicket happens prior to you adding the SupportTicketNote
e.g.
SupportTicket st = new SupportTicket();
SupportTicketNote stn = new SupportTicketNote();
///Code to set properties on both objects
st.Save();
st.SupportTicketNotes.Add(stn);
st.Save();

ArgumentOutOfRangeException : Index was out of range

I'm getting this weird ArgumentOutOfRangeException whenever I use the
PersitenceSpecification class for verifying an entity that has a
reference to a value object.
public class CatalogItem : DomainEntity
{
internal virtual Manufacturer Manufacturer { get; private
set; }
internal virtual String Name { get; private set; }
protected CatalogItem()
{}
public CatalogItem(String name, String manufacturer)
{
Name = name;
Manufacturer = new Manufacturer(manufacturer);
}
}
public class CatalogItemMapping : ClassMap<CatalogItem>
{
public CatalogItemMapping()
{
Id(catalogItem => catalogItem.Id);
Component<Manufacturer>(category => category.Manufacturer,
m => m.Map(manufacturer =>
manufacturer.Name));
Map(catalogItem => catalogItem.Name);
Map(Reveal.Property<CatalogItem>("Price"));
}
}
[TestFixture]
public class When_verifying_the_class_mapping_of_a_catalog_item
: NHibernateSpecification
{
[Test]
public void Then_a_catalog_object_should_be_persistable()
{
new PersistenceSpecification<CatalogItem>(Session)
.VerifyTheMappings();
}
}
[TestFixture]
public class NHibernateSpecification
: Specification
{
protected ISession Session { get; private set; }
protected override void Establish_context()
{
var configuration = new SQLiteConfiguration()
.InMemory()
.ShowSql()
.ToProperties();
var sessionSource = new SessionSource(configuration, new
RetailerPersistenceModel());
Session = sessionSource.CreateSession();
sessionSource.BuildSchema(Session);
ProvideInitialData(Session);
Session.Flush();
Session.Clear();
}
protected override void Dispose_context()
{
Session.Dispose();
Session = null;
}
protected virtual void ProvideInitialData(ISession session)
{}
}
Here's the error I'm getting:
TestCase
'Then_a_catalog_object_should_be_persistable' not executed:
System.ArgumentOutOfRangeException :
Index was out of range. Must be
non-negative and less than the size of
the collection. Parameter name: index
at System.ThrowHelper.ThrowArgumentOutOfRangeException
(ExceptionArgument argument,
ExceptionResource resource)
at System.ThrowHelper.ThrowArgumentOutOfRangeException()
at System.Collections.Generic.List1.get_Item(Int32
index)
at System.Data.SQLite.SQLiteParameterCollection.GetParameter(Int32
index)
at System.Data.Common.DbParameterCollection.System.Collections.IList.get_Item
(Int32 index)
at NHibernate.Type.GuidType.Set(IDbCommand
cmd, Object value, Int32 index)
at NHibernate.Type.NullableType.NullSafeSet(IDbCommand
cmd, Object value, Int32 index)
at NHibernate.Type.NullableType.NullSafeSet(IDbCommand
st, Object value, Int32 index,
ISessionImplementor session)
at NHibernate.Persister.Entity.AbstractEntityPersister.Dehydrate
(Object id, Object[] fields, Object
rowId, Boolean[] includeProperty,
Boolean[][] includeColumns, Int32
table, IDbCommand statement,
ISessionImplementor session, Int32
index)
at NHibernate.Persister.Entity.AbstractEntityPersister.Insert(Object
id, Object[] fields, Boolean[]
notNull, Int32 j, SqlCommandInfo sql,
Object obj, ISessionImplementor
session)
at NHibernate.Persister.Entity.AbstractEntityPersister.Insert(Object
id, Object[] fields, Object obj,
ISessionImplementor session)
at NHibernate.Action.EntityInsertAction.Execute()
at NHibernate.Engine.ActionQueue.Execute(IExecutable
executable)
at NHibernate.Engine.ActionQueue.ExecuteActions(IList
list)
at NHibernate.Engine.ActionQueue.ExecuteActions()
at NHibernate.Event.Default.AbstractFlushingEventListener.PerformExecutions
(IEventSource session)
at NHibernate.Event.Default.DefaultFlushEventListener.OnFlush
(FlushEvent event)
at NHibernate.Impl.SessionImpl.Flush()
at NHibernate.Transaction.AdoTransaction.Commit()
d:\Builds\FluentNH\src\FluentNHibernate\Testing
\PersistenceSpecification.cs(127,0):
at
FluentNHibernate.Testing.PersistenceSpecification1.TransactionalSave
(Object propertyValue)
d:\Builds\FluentNH\src\FluentNHibernate\Testing
\PersistenceSpecification.cs(105,0):
at
FluentNHibernate.Testing.PersistenceSpecification`1.VerifyTheMappings
()
C:\Source\SupplyChain\Tests\Retailer.IntegrationTests\Mappings
\CatalogItemMappingSpecifications.cs(14,0):
at
SupplyChain.Retailer.IntegrationTests.Mappings.When_verifying_the_class_mapping_of_a_catalog_item.Then_a_catalog_object_should_be_persistable
()
Sorry for the long post, but this one got me busy for a couple of
hours now. This might not be caused by FNH as I found this JIRA ticket
of NH itself that mentions something similar:
http://forum.hibernate.org/viewtopic.php?p=2395409
I'm still hoping that I'm doing something wrong in my code :-). Any
thought?
Thanks in advance
I found the solution to this problem which resulted from my own
stupidity in the first place. It all became clear to me as soon as I
generated the hbm files from the fluent NH mapping.
<class name="CatalogItem" table="`CatalogItem`" xmlns="urn:nhibernate-
mapping-2.2" optimistic-lock="version">
...
<property name="Name" length="100" type="String">
<column name="Name" />
</property>
...
<component name="Manufacturer" insert="false" update="true">
<property name="Name" length="100" type="String">
<column name="Name" />
</property>
</component>
</class>
Notice that the column for the Name property and the column for the
Manufacturer component are both mapped to the same column. That's why
this resulted into an ArgumentOutOfRangeException, because there were
more arguments than there were column names. I solved this by
explicitely specifying a column name for the component mapping:
Component(catalogItem => catalogItem.Manufacturer,
m => m.Map(manufacturer => manufacturer.Name,
"Manufacturer"));
Another lesson learned.
In my case, I was mapping two properties to the same column with Fluent NHibernate.
Your CatalogItem doesn't seem to have a Price property, which seems odd when you're using the Reveal helper.
Yes, I removed that one for reducing some of the noise. I guess I forgot to remove it from the mapping as well. After doing some more investigation, I noticed that it has something to do with Manufacturer being mapped as a component. When I used a plain-old string instead of a separate class, everything works fine.
In my particular case I was adding property as well as ID (using attributes) over the same .NET property. This resulted in the same error.
Old question, but if someone runs into the same problem as I did, it may help to know that this Fluent Nhibernate issue (ColumnPrefix only applied to first Component mapping inside a ComponentMap) can give the same exception since the columns prefixes are not always applied.
The other answers for this question are correct. But there is another case where NHibernate outputs the same message with different stack trace. The stack trace can be found in this question.
As this is one of the top questions that popup when I search online with exact error message, I thought it would be helpful for others to know how I fixed it. There is a documented issue for this error on NHibernate's GitHub repository. Here is the link - https://github.com/nhibernate/nhibernate-core/issues/1319.
The error has been fixed in latest NHibernate at the time of writing this answer. For older versions such as 3.1.0 (the version I was working with when facing the error), setting format_sql property to false in nhibernate.config file fixes the issue. More details about the error and workaround can be found in the GitHub issue and NHibernate doc.