tags:

views:

1936

answers:

4

I've just discovered that if I get an object from an NHibernate session and change a property on object, NHibernate will automatically update the object on commit without me calling Session.Update(myObj)!

I can see how this could be helpful, but as default behaviour it seems crazy!

Update: I now understand persistence ignorance, so this behaviour is now clearly the preferred option. I'll leave this now embarrassing question here to hopefully help other profane users.

How can I stop this happening? Is this default NHib behaviour or something coming from Fluent NHibs AutoPersistenceModel?

If there's no way to stop this, what do I do? Unless I'm missing the point this behaviour seems to create a right mess.

Im using NHibernate 2.0.1.4 and a Fluent NHib build from 18/3/2009

Edit, is this guy right with his answer?

Edit: I've also read that overriding an Event Listener could be a solution to this. However, IDirtyCheckEventListener.OnDirtyCheck isn't called in this situation. Does anyone know which listener I need to override?

Thanks

Andrew

+5  A: 

You can set Session.FlushMode to FlushMode.Never. This will make your operations explicit

ie: on tx.Commit() or session.Flush(). Of course this will still update the database upon commit/flush. If you do not want this behavior, then call session.Evict(yourObj) and it will then become transient and NHibernate will not issue any db commands for it.

Response to your edit: Yes, that guy gives you more options on how to control it.

Ben Scheirman
yeah but it will still happen when I do flush.
Andrew Bullock
ahh, then make the object transient by doing Session.Evict()
Ben Scheirman
I get the feeling nhibernate doesnt want me to control updates manually, all these solutions seem like hacks. why is this?
Andrew Bullock
because you can save an entire aggregate by calling save on the root entity. Saves can be cascaded to other objects. In addition, NH knows how to keep references from other objects in sync, so you don't save duplicates for example.
Ben Scheirman
oooook... I'm afraid im still not getting this 100%. I know what my cascade rules are, if im calling update then i should be aware of whats gonna happen, nh shouldn't try and save me from my own stupidity with strange features
Andrew Bullock
I think we need more details on what you're doing to give you a better answer. NH issues queries at the last possible moment, so it apparently *needs* it at the time when the query happens. otherwise it waits for tx.commit or session.flush.
Ben Scheirman
+1  A: 

Calling SaveOrUpdate() or Save() makes an object persistent. If you've retrieved it using an ISession or from a reference to a persistent object, then the object is persistent and flushing the session will save changes. You can prevent this behavior by calling Evict() on the object which makes it transient.

Edited to add: I generally consider an ISession to be a unit of work. This is easily implemented in a web app. using session-per-request but requires more control in WinForms.

Jamie Ide
After I Evict, can I manually do an update on the object? Is this whole approach a good idea? Is there some way to make this default behaviour for all objects or do i have to evict each one?
Andrew Bullock
After you Evict, the object is transient. To make it persistent again, you can call SaveOrUpdate on it.
Jamie Ide
I think you're trying to fight the session as a unit of work. There is a way to re-attach, but you should probably just rely on tighter session lifecycles. In a web app, this would be per request, in a smart client it would be per-unit-of-work.
Ben Scheirman
Ok, thanks for your help, I cant help feeling like this is a hacky solution though. Cant i just set NHibernate.DoThingsWithoutMeAsking = false; somewhere?
Andrew Bullock
Im in a webapp and have a UoW setup to commit on End_Request. My specific case is where i update an object from an edit screen, then validate it. If it fails validation i throw it back with errors, if it passes then i call save. Thing is its still saved on a failed validation because of this issue!
Andrew Bullock
In that case, I think the rule is: If the object doesn't fit, then you must Evict. If you weren't using session-per-request then you would control the UOW by calling Flush() on it.
Jamie Ide
Yes, you can either evict the object or change the EndREquest behavior to tx.Rollback or session.clear before disposing of it, so that you have the semantics of unless-I-commit-the-changes-they-don't-happen.
Ben Scheirman
@Ben, yes this seems like my only solution. It feels hacky though :s
Andrew Bullock
+2  A: 

A first solution (hack to be honest), is availaible here (http://code.google.com/p/unhaddins/source/browse/#svn/trunk/uNhAddIns/uNhAddIns/Listeners/AutoDirtyCheck) but it is incomplete.

Nelson
Discussion on nhibernate google group here http://groups.google.com/group/nhusers/browse_thread/thread/11e5ff4c27006c4b
Nelson
also http://fabiomaulo.blogspot.com/2009/03/ensuring-updates-on-flush.html
Mauricio Scheffer
A: 

Hi folks,

even though this is quite old a thread already, I still have not found a decent solution up to now.

However, what just came to my mind is as follows:

  • for all objects to be maintained by hibernate, create a property 'IsDirty', which defaults to false
  • create an interceptor which overrides FindDirty and states the object only to be dirty if the according flag is set
  • do not call the DAO's SaveOrUpdate directly, but write a wrapper around it and set the IsDirty flag once call

Therefore, objects will never go to the database without the wrapping save method having been called before.

Any thoughts are mor than appreciated!

Regards

bonifaz
actually this whole discussion is wrong. Why change an object's property value if you don't plan to save it?
Jaguar
Why do users change their mind ?
Nelson
Definitely, [N]Hibernate has a concept behind these behaviors which makes sense and is consistent, so any solution should go in line with that concepts (which in this case means: Evict the object from the session). Don't circumvent the concept by defining wrapper save methods and such stuff.
chiccodoro