5
votes

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

7

7 Answers

15
votes

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.

2
votes

In my case, I was mapping two properties to the same column with Fluent NHibernate.

0
votes

Your CatalogItem doesn't seem to have a Price property, which seems odd when you're using the Reveal helper.

0
votes

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.

0
votes

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.

0
votes

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.

0
votes

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.