Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

null id in 'xxx' entry (don't flush the Session after an exception occurs) when using session.Merge() to save graph #2973

Closed
QuangVinhTran opened this issue Jan 5, 2022 · 3 comments

Comments

@QuangVinhTran
Copy link

QuangVinhTran commented Jan 5, 2022

We are using Nhibernate version 5.3.6, and we got the below exception when using session.Merge() to save graph (where there are some new child entites). We don't get this error with version 5.2.x. Any helps for this error?

NHibernate.AssertionFailure: null id in 'xxx' entry (don't flush the Session after an exception occurs)
at NHibernate.Event.Default.DefaultFlushEntityEventListener.CheckId(Object obj, IEntityPersister persister, Object id)
at NHibernate.Event.Default.DefaultFlushEntityEventListener.GetValues(Object entity, EntityEntry entry, Boolean mightBeDirty, ISessionImplementor session)
at NHibernate.Event.Default.DefaultFlushEntityEventListener.OnFlushEntity(FlushEntityEvent event)
at NHibernate.Event.Default.AbstractFlushingEventListener.FlushEntities(FlushEvent event)
at NHibernate.Event.Default.AbstractFlushingEventListener.FlushEverythingToExecutions(FlushEvent event)
at NHibernate.Event.Default.DefaultAutoFlushEventListener.OnAutoFlush(AutoFlushEvent event)
at NHibernate.Impl.SessionImpl.AutoFlushIfRequired(ISet`1 querySpaces)
at NHibernate.Impl.SessionImpl.List[T](CriteriaImpl criteria)
at NHibernate.Impl.CriteriaImpl.List[T]()
at NHibernate.Impl.CriteriaImpl.List()
at WriteHistoryForFaktorNotVorgemerktByKeyNummer(ISession session, Boolean isKanton, Int32 keyNr) in FaktorHistoryWriter.cs:line 113
at AllSessionsInterceptor.OnSave(Object entity, Object id, Object[] state, String[] propertyNames, IType[] types) in Data\DataAccess\AllSessionsInterceptor.cs:line 239
at NHibernate.Event.Default.AbstractSaveEventListener.SubstituteValuesIfNecessary(Object entity, Object id, Object[] values, IEntityPersister persister, ISessionImplementor source)
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.DefaultMergeEventListener.MergeTransientEntity(Object entity, String entityName, Object requestedId, IEventSource source, IDictionary copyCache)
at NHibernate.Event.Default.DefaultMergeEventListener.EntityIsTransient(MergeEvent event, IDictionary copyCache)
at NHibernate.Event.Default.DefaultMergeEventListener.OnMerge(MergeEvent event, IDictionary copiedAlready)
at NHibernate.Impl.SessionImpl.FireMerge(IDictionary copiedAlready, MergeEvent event)
at NHibernate.Impl.SessionImpl.Merge(String entityName, Object obj, IDictionary copiedAlready)
at NHibernate.Engine.CascadingAction.MergeCascadingAction.Cascade(IEventSource session, Object child, String entityName, Object anything, Boolean isCascadeDeleteEnabled)
at NHibernate.Engine.Cascade.CascadeToOne(Object parent, Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled)
at NHibernate.Engine.Cascade.CascadeCollectionElements(Object parent, Object child, CollectionType collectionType, CascadeStyle style, IType elemType, Object anything, Boolean isCascadeDeleteEnabled)
at NHibernate.Engine.Cascade.CascadeCollection(Object parent, Object child, CascadeStyle style, Object anything, CollectionType type)
at NHibernate.Engine.Cascade.CascadeAssociation(Object parent, Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled)
at NHibernate.Engine.Cascade.CascadeOn(IEntityPersister persister, Object parent, Object anything)
at NHibernate.Event.Default.DefaultMergeEventListener.CascadeOnMerge(IEventSource source, IEntityPersister persister, Object entity, IDictionary copyCache)
at NHibernate.Event.Default.DefaultMergeEventListener.EntityIsDetached(MergeEvent event, IDictionary copyCache)
at NHibernate.Event.Default.DefaultMergeEventListener.OnMerge(MergeEvent event, IDictionary copiedAlready)
at NHibernate.Impl.SessionImpl.FireMerge(IDictionary copiedAlready, MergeEvent event)
at NHibernate.Impl.SessionImpl.Merge(String entityName, Object obj, IDictionary copiedAlready)
at NHibernate.Engine.CascadingAction.MergeCascadingAction.Cascade(IEventSource session, Object child, String entityName, Object anything, Boolean isCascadeDeleteEnabled)
at NHibernate.Engine.Cascade.CascadeToOne(Object parent, Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled)
at NHibernate.Engine.Cascade.CascadeCollectionElements(Object parent, Object child, CollectionType collectionType, CascadeStyle style, IType elemType, Object anything, Boolean isCascadeDeleteEnabled)
at NHibernate.Engine.Cascade.CascadeCollection(Object parent, Object child, CascadeStyle style, Object anything, CollectionType type)
at NHibernate.Engine.Cascade.CascadeAssociation(Object parent, Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled)
at NHibernate.Engine.Cascade.CascadeOn(IEntityPersister persister, Object parent, Object anything)
at NHibernate.Event.Default.DefaultMergeEventListener.CascadeOnMerge(IEventSource source, IEntityPersister persister, Object entity, IDictionary copyCache)
at NHibernate.Event.Default.DefaultMergeEventListener.EntityIsDetached(MergeEvent event, IDictionary copyCache)
at NHibernate.Event.Default.DefaultMergeEventListener.OnMerge(MergeEvent event, IDictionary copiedAlready)
at NHibernate.Event.Default.DefaultMergeEventListener.OnMerge(MergeEvent event)
at NHibernate.Impl.SessionImpl.FireMerge(MergeEvent event)
at NHibernate.Impl.SessionImpl.Merge(String entityName, Object obj)
at NHibernate.Impl.SessionImpl.Merge[T](T entity)
@bahusoid
Copy link
Member

bahusoid commented Jan 5, 2022

Most likely caused by #1754

So it seems inside Merge operation your interceptor tries to load some data. And auto flush logic executed before query tries to perform session flush that leads to this exception.

You can try to disable auto flush logic inside your interceptor by temporary setting session.FlushMode to Commit or Manual value.

@QuangVinhTran
Copy link
Author

With our case, in the interceptor, we want to take the "id" of new entity to call the store procedure to do some business. If we use session.FlushMode to Commit or Manual value, can we get the "id" of new entity ?

@bahusoid
Copy link
Member

bahusoid commented Jan 7, 2022

With our case, in the interceptor, we want to take the "id" of new entity

Hm.. So after #1754 entity DB insert for Merge is delayed till flush and id is not yet available in IInterceptor.OnSave (which seems wasn't really designed for your use case as description states "Called before an object is saved". It's clearly was not true for objects with identity id. Now it actually behaves as described) This behavior was already discussed in #2632 (though this case shows that it also can lead to some unexpected exception)

Issue aside it seems more proper place for your case is using IPostInsertEventListener (add your custom class to configuration.EventListeners.PostInsertEventListeners) as it's always called after entity is already inserted.

@hazzik hazzik closed this as not planned Won't fix, can't repro, duplicate, stale Aug 2, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants