Skip to content

NH-3362 - Initializing a bag after queued add causes incorrect behavior #1295

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

Closed
nhibernate-bot opened this issue Oct 12, 2017 · 1 comment
Closed

Comments

@nhibernate-bot
Copy link
Collaborator

Boris Drajer created an issue — 27th December 2012, 10:04:54:

I haven't been able to reproduce the complete behavior in unit tests, but hopefully this will be enough to find the cause.

The sequence of actions is this:

  1. Load an entity with a lazy one-to-many bag
  2. Add a new (unsaved) object to the yet-uninitialized bag. The add is queued for later.
  3. Initialize the bag with NHibernateUtil.Initialize()

At this point, the collection creates a snapshot of its contents, and the snapshot contains the unsaved object from step 2 - which I believe is wrong.

A consequence of this is that if I --
4. Remove the newly added unsaved object from collection
5. Flush the session

-- I get an exception saying "object references an unsaved transient instance - save the transient instance before flushing or set cascade action for the property to something that would make it autosave." The exception is thrown by NHibernate.Engine.ForeignKeys.GetEntityIdentifierIfNotUnsaved(), and the reason why this happens is that the AbstractPersistentCollection.GetOrphans() method receives this unsaved object in the oldElements collection, which I believe should never happen (oldElements should contain the state present in the database?) This was caused by the incorrect snapshot in the collection in step 3.

I was able to reproduce only the incorrect snapshot in the unit test. The later exception appears in my application but I cannot figure out which combination of mappings triggers it, probably a multiple cascade of delete-orphan relations. In any case, when I reverse the order of steps 2 and 3 - that is, initialize the collection before adding the object - the problem disappears.

I suppose the solution would be to somehow modify the code to create the collection snapshot before the queued actions are replayed, but I have no idea if this is correct or how it could be properly done.

There are two files attached that reproduce the incorrect snapshot. It's a modified version of the existing generic bag test, include it in NHibernate.Test/GenericTest/BagGeneric and run the supplied method.

Environment: .Net framework 3.5 SP1, SQL Server 2005 dialect running on a SQL Server 2008.

As a side note, it seems to me that the exception in the GetEntityIdentifierIfNotUnsaved() method is a bit misplaced, I'm mentioning it here because this is a good illustration why: the method doesn't really know the reason for the error, the message is just a guess. The problem here is not that something needs to be saved or cascaded but that the collection state is corrupt. I think it would be better if the error is handled in a caller method (possibly by catching this exception and providing a better message). This part is related to NH-2070 - I can create a separate issue for this if appropriate.


Adrian Walters added a comment — 20th May 2013, 19:22:18:

We are experiencing a similar issue, where adding and then removing an item to a colleciton causes an exception when NH attempts to flush changes. Is there any estimate when this bug will be addressed?

@fredericDelaporte
Copy link
Member

#1878, merged in v5.2, does no more allow to reproduce the "snapshot contains non persisted entity" part of this report.

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