I had a pretty typical situation where you'd store an object in a cache like ASP.NET Session to work with it until it comes time to save the data to the database. Poking around the forums I found a post and also some other blogs that stated that you can call SaveOrUpdate to reattach an entity to the current NHibernate ISession. I kept getting a NonUniqueObjectException though which is just saying that the entity has already been loaded into the current NHibernate Session and cannot be Saved. Here's the flow and how NHibernate works with it:
1. Load Object from database and store into ASP.NET to work with the object.
2. So some real exciting stuff in the web page to manipulate data in store object.
3. Time to persist the object to the database, so let's reattach the object to the current NHibernate ISession using SaveOrUpdate
4. FAILS and throw NonUniqueObjectException for an entity that is a CHILD of my object...
Now at this point I was wondering if perhaps the calls weren't traversing my object graph (into my child objects). Looking thru the StackTrace it turns out a call to DoUpdateMutable in SessionImpl is checking for uniqueness AFTER it has already saved the entity which of course would fail (Updating the object reattaches the entity to the ISession).
But when I looked at the explicit Update() call, it looked like it might work. BLAM! No problems and the object was reattached and saved just like it should be. SUCCESS! Incidentally, a call to Lock() would have worked too but there might be problems with this...here are some rules I discovered while researching this:
1. A call to Lock() will lose your changes on an Intransient Instance (one that was in the DB at some point). Reserve Lock(Object, LockMode.NONE) for attaching INtransient (new) instances to the current ISession. This is rare. If you choose to use Lock() be sure to make all changes to your entity AFTER the Lock() call or else you'll lose them during persistence.
2. NHibernate WILL traverse your object graph for Lock() and Evict() if you set your cascade to 'all' or 'all-delete-orphan'. So if you need to pull the entity out it shoudl be fine for the child objects if use these cascade strategies...otherwise any associations to your target entity will need to be explicitly Evict()ed or Lock()ed.
It would be nice if there was an explicit Reattach() call in the ISession interface but it works.
This failure to reattach by SaveOrUpdate may be a bug...I'll repost if I hear anything in the forum.