简体   繁体   中英

Can Native generated value-type identifier be null in NHibernate?

I have a NHibernate mapping on top of a monolithic, legacy, database, and since we rolled out in production we have sporadiclly getting errors from NHibernate in about 4-8 times a day, with about 60 000 events per day processed, so the error frequency is about 0.006% - 0.013%).

As far as I and my colleagues have been able to determine, there's nothing that is different with these failing events/messages compared to the ones that succeed.

The error we're getting is

NHibernate.AssertionFailure: null identifier
at NHibernate.Engine.EntityKey..ctor(Object identifier, String rootEntityName, String entityName, IType identifierType, Boolean batchLoadable, ISessionFactoryImplementor factory, EntityMode entityMode)
at NHibernate.Engine.EntityKey..ctor(Object id, IEntityPersister persister, EntityMode entityMode)
at NHibernate.Event.Default.AbstractSaveEventListener.PerformSaveOrReplicate(Object entity, EntityKey key, IEntityPersister persister, Boolean useIdentityColumn, Object anything, IEventSource source, Boolean requiresImmediateIdAccess)
at NHibernate.Event.Default.AbstractSaveEventListener.PerformSave(Object entity, Object id, IEntityPersister persister, Boolean useIdentityColumn, Object anything, IEventSource source, Boolean requiresImmediateIdAccess)
at NHibernate.Event.Default.AbstractSaveEventListener.SaveWithGeneratedId(Object entity, String entityName, Object anything, IEventSource source, Boolean requiresImmediateIdAccess)
at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.SaveWithGeneratedOrRequestedId(SaveOrUpdateEvent event)
at NHibernate.Event.Default.DefaultSaveEventListener.SaveWithGeneratedOrRequestedId(SaveOrUpdateEvent event)
at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.EntityIsTransient(SaveOrUpdateEvent event)
at NHibernate.Event.Default.DefaultSaveEventListener.PerformSaveOrUpdate(SaveOrUpdateEvent event)
at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.OnSaveOrUpdate(SaveOrUpdateEvent event)
at NHibernate.Impl.SessionImpl.FireSave(SaveOrUpdateEvent event)
at NHibernate.Impl.SessionImpl.Save(Object obj)

But the identifier column is a value type (System.Int32), using Native generator. How can it be null?

public class MyItem {
   public int MyItemId { get; set; }
}

public class MyItemMap : ClassMapping<MyItem>
{
    public MyItemMap ()
    {
        Table("MyItemTable");

        Id(m => m.MyItemId, x =>
        {
            x.Column("MyItem_ID");
            x.Generator(Generators.Native);
            x.UnsavedValue(default(int));
        });
    }
}

So, my question is really; a) Why is NHibernate complain about a null identifier when the identifier is a value type (ie not nullable), ? b) Is there anything I can do about it?

I was able to isolate and reproduce the issue.

The table in question (MyItemTable) had a index with IGNORE_DUP_KEY=ON.

And due to another issue, we we're trying to insert a near identical row twice. The second time the insert fails with an warning, and no row is actually inserted. So when NHibernate tries to get the generated identity, SQL Server probably returns NULL since no record was inserted.

The reason why this did not show up in any tests first was due to the fact that the database has not been versioned by tools from the start, but by manual migration. Also, the index was not included when our db versioning tool scripted the legacy database. The index was therefor missing in the testing environment/database generated for integration tests. The headaches of monolithic legacy stuff...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM