12

I have the following mappings:

public class SecurityMap : ClassMap<Security>
    {
        public SecurityMap()
        {
            Table("Security");
            CompositeId().KeyProperty(k => k.Id, "SecurityId").KeyProperty(k => k.EndDate);
            Map(x => x.LastUpdateUser);
            References(x => x.Company).Columns("CompanyId", "EndDate");
            References(x => x.PrimaryListing).Columns("PrimaryListingId", "EndDate");
         }
    }

public class ListingMap : ClassMap<Listing>
    {
        public ListingMap()
        {
            Table("Listing");
            CompositeId().KeyProperty(k => k.Id, "ListingID").KeyProperty(k => k.EndDate);
            References(x => x.Security).Columns("SecurityId","EndDate");
        }
    }

 public class CompanyMap : ClassMap<Company>
    {
        public CompanyMap()
        {
            Table("Company");
            CompositeId().KeyProperty(k => k.Id, "CompanyID").KeyProperty(k => k.EndDate);
            HasMany(x => x.Securities).KeyColumns.Add("CompanyId", "EndDate");
        }       
    }

When I attempt to run this test:

[Test]
public void can_update_a_security()
{
    var repo = IoC.Resolve<ISecurityRepository>();
    int someSecurity = 1;
    using (var work = IoC.Resolve<IUnitOfWorkManager>().Current)
    {
        Security security = repo.Get(someSecurity);
        security.ShouldNotBeNull();
        security.LastUpdateUser = "Dirk Diggler" + DateTime.Now.Ticks;
        repo.Save(security);
        work.Commit();
    }
}

I get the following error deep in the bowels of NHibernate:

Execute System.IndexOutOfRangeException: Invalid index 6 for this SqlParameterCollection with Count=6. at System.Data.SqlClient.SqlParameterCollection.RangeCheck(Int32 index) at System.Data.SqlClient.SqlParameterCollection.GetParameter(Int32 index) at System.Data.Common.DbParameterCollection.System.Collections.IList.get_Item(Int32 index) s:\NHibernate\NHibernate\src\NHibernate\Type\DateTimeType.cs(65,0): at NHibernate.Type.DateTimeType.Set(IDbCommand st, Object value, Int32 index) s:\NHibernate\NHibernate\src\NHibernate\Type\NullableType.cs(180,0): at NHibernate.Type.NullableType.NullSafeSet(IDbCommand cmd, Object value, Int32 index) s:\NHibernate\NHibernate\src\NHibernate\Type\NullableType.cs(139,0): at NHibernate.Type.NullableType.NullSafeSet(IDbCommand st, Object value, Int32 index, ISessionImplementor session) s:\NHibernate\NHibernate\src\NHibernate\Type\ComponentType.cs(213,0): at NHibernate.Type.ComponentType.NullSafeSet(IDbCommand st, Object value, Int32 begin, ISessionImplementor session) s:\NHibernate\NHibernate\src\NHibernate\Persister\Entity\AbstractEntityPersister.cs(2393,0): at NHibernate.Persister.Entity.AbstractEntityPersister.Dehydrate(Object id, Object[] fields, Object rowId, Boolean[] includeProperty, Boolean[][] includeColumns, Int32 table, IDbCommand statement, ISessionImplementor session, Int32 index) s:\NHibernate\NHibernate\src\NHibernate\Persister\Entity\AbstractEntityPersister.cs(2754,0): at NHibernate.Persister.Entity.AbstractEntityPersister.Update(Object id, Object[] fields, Object[] oldFields, Object rowId, Boolean[] includeProperty, Int32 j, Object oldVersion, Object obj, SqlCommandInfo sql, ISessionImplementor session) s:\NHibernate\NHibernate\src\NHibernate\Persister\Entity\AbstractEntityPersister.cs(2666,0): at NHibernate.Persister.Entity.AbstractEntityPersister.UpdateOrInsert(Object id, Object[] fields, Object[] oldFields, Object rowId, Boolean[] includeProperty, Int32 j, Object oldVersion, Object obj, SqlCommandInfo sql, ISessionImplementor session) s:\NHibernate\NHibernate\src\NHibernate\Persister\Entity\AbstractEntityPersister.cs(2940,0): at NHibernate.Persister.Entity.AbstractEntityPersister.Update(Object id, Object[] fields, Int32[] dirtyFields, Boolean hasDirtyCollection, Object[] oldFields, Object oldVersion, Object obj, Object rowId, ISessionImplementor session) s:\NHibernate\NHibernate\src\NHibernate\Action\EntityUpdateAction.cs(78,0): at NHibernate.Action.EntityUpdateAction.Execute() s:\NHibernate\NHibernate\src\NHibernate\Engine\ActionQueue.cs(130,0): at NHibernate.Engine.ActionQueue.Execute(IExecutable executable) s:\NHibernate\NHibernate\src\NHibernate\Engine\ActionQueue.cs(113,0): at NHibernate.Engine.ActionQueue.ExecuteActions(IList list) s:\NHibernate\NHibernate\src\NHibernate\Engine\ActionQueue.cs(147,0): at NHibernate.Engine.ActionQueue.ExecuteActions() s:\NHibernate\NHibernate\src\NHibernate\Event\Default\AbstractFlushingEventListener.cs(241,0): at NHibernate.Event.Default.AbstractFlushingEventListener.PerformExecutions(IEventSource session) s:\NHibernate\NHibernate\src\NHibernate\Event\Default\DefaultFlushEventListener.cs(19,0): at NHibernate.Event.Default.DefaultFlushEventListener.OnFlush(FlushEvent event) s:\NHibernate\NHibernate\src\NHibernate\Impl\SessionImpl.cs(1478,0): at NHibernate.Impl.SessionImpl.Flush() s:\NHibernate\NHibernate\src\NHibernate\Transaction\AdoTransaction.cs(187,0): at NHibernate.Transaction.AdoTransaction.Commit() at lambda_method(ExecutionScope , ITransaction )

Now the interesting thing is if I comment out the reference to Company or PrimaryListing in the SecurityMap, I don't get the error. It doesn't seem to matter which I comment out. The error only happens when I have both.

When the update actually goes through NHProf shows me this update:

UPDATE Security
SET    LastUpdateUser = '2010-02-19T08:09:24.00' /* @p0 */,
       CompanyId = 54199 /* @p1 */,
       EndDate = '9999-12-31T00:00:00.00' /* @p2 */
WHERE  SecurityId = 1 /* @p3 */
       AND EndDate = '9999-12-31T00:00:00.00' /* @p4 */

I am not sure why it is updating CompanyId and EndDate, but I suspect it is related.

Any one have ideas? Work arounds would be greatly appreciated.

Jaguar
  • 5,929
  • 34
  • 48
NotMyself
  • 29,209
  • 17
  • 56
  • 74

1 Answers1

30

Yes its a common problem, you are using the Column "EndDate" twice in your mapping definition (for both Company and PrimaryListing) and that is not allowed. One of them has to go, or have an additional EndDate column (one for each association)

check this too nHibernate 2.0 - mapping a composite-id *and* many-to-one relationship causes "invalid index" error

and http://devlicio.us/blogs/derik_whittaker/archive/2009/03/19/nhibernate-and-invalid-index-n-for-this-sqlparametercollection-with-count-n-error.aspx

Community
  • 1
  • 1
Jaguar
  • 5,929
  • 34
  • 48
  • 2
    Do you know if this eventually will be fixed? It renders NH unusable for more complex scenarios involving partitioned tables... – Daniel Hilgarth Mar 07 '12 at 12:49
  • It looks like this is still an issue even with NH 4.0 – leojh Dec 18 '14 at 01:49
  • @LeoHernandez this is not an issue. For all intents and purposes, if you want to use one column for multiple properties, then you are doing it wrong – Jaguar Dec 18 '14 at 17:47
  • 1
    @Jaguar I would agree with you except the scenario I encountered is one where one of the fields part of the composite key is used as a FK to another composite. When you map the Composite Id then again for the FK NH throws this error. NH should not consider fields mapped as part of the composite key as "duplicate" in this scenario. Then again it's a messed up legacy db and you can't expect it to do it all. I came up with a good compromise . – leojh Dec 19 '14 at 01:23
  • @LeoHernandez ah yes I guess this is a valid scenario – Jaguar Dec 29 '14 at 15:12