While I was developing for my customer I suddenly received a NonUniqueObjectException while deleting some data.
NHibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: 58372, of class: …
The problem I suffered from was that I was deleting the “same” object twice. The issue is that NHibernate knows that these objects are the same, although the objects have different object references.
One of my objects was a detached object that came from and was deleted in the GUI. The second object came from a fetch of data to fill a non-mapped collection. The objects in this collection have a reference to the object we want to delete. Because this reference was mapped, an instance of this object is fetched from the DB.
So when this collection is fetched, and then we try to delete the detached object, we receive the NonUniqueObjectException. The solution for this is to find a way to attach the detached object to the NHibernate session before I fetch the collection. But when you look for it into the IDaoPersister interface, you won’t find any “Attach'” method.
After some quality time spent on Google I discovered the following in the Hibernate documentation:
Use update() if you are certain that the session does not contain an already persistent instance with the same identifier. Use merge() if you want to merge your modifications at any time without consideration of the state of the session. In other words, update() is usually the first method you would call in a fresh session, ensuring that the reattachment of your detached instances is the first operation that is executed.
This means you can use the update() method to reattach your detached objects to the session. The update() method won’t trigger any update queries to the DB. These update queries will only be executed when the Flush() method is called on the session and NHibernates discovers properties that have been changed on the object.
Before I retrieve my collection I call the update() method with my detached object as parameter. This way the object is stored in the NHibernate cache and won’t be retrieved from the database when needed.