Can I disable automatic updating of dirty objects?

426 views
Skip to first unread message

steves

unread,
Jul 24, 2009, 9:08:47 AM7/24/09
to nhusers
Hi,

I have been searching the web for some solution to this thing: I just
want NHibernate to check and eventually update only these etities that
I explicitly want to be updated using ISession.SaveOrUpdate
(updateMeAndOnlyMe) and I would want some "nice" solution, not hacky
like "Evict every entity retrieved from database".

I found these two discussions, but neither explains some real solution

http://groups.google.com/group/nhibernate-development/browse_thread/thread/d056160cdfe790f
http://stackoverflow.com/questions/673564/nhibernates-automatic-dirty-checking-update-behaviour-turning-it-off

Is there any progress in this? Do NHibernate developers plan to add
something like configuration option or plugin that would do that and
which would be part of NHibernate or at least NHibernate contrib?

steves

unread,
Jul 24, 2009, 9:11:42 AM7/24/09
to nhusers
> I just want NHibernate to check and eventually update only these etities that
> I explicitly want to be updated using ISession.SaveOrUpdate(updateMeAndOnlyMe)

Here I mean when ISession.Flush() is called.

Fabio Maulo

unread,
Jul 24, 2009, 9:51:02 AM7/24/09
to nhu...@googlegroups.com
http://fabiomaulo.blogspot.com/2009/03/ensuring-updates-on-flush.html
The solution is now available and completed in uNhAddIns



--
Fabio Maulo

Fernando Zago

unread,
Jul 24, 2009, 11:20:51 AM7/24/09
to nhu...@googlegroups.com
Arg... some one can explain step by step how to implement this

configuration.RegisterDisableAutoDirtyCheckListeners();

I'm not smart enough! =(
---
A vida me ensinou a nunca desistir,
nem ganhar, nem perder mas procurar evoluir.
Podem me tirar tudo que tenho!
Só não podem me tirar as coisas boas que eu já fiz pra quem eu amo!
E eu sou feliz e canto e o universo é uma canção eu vou que vou!

Fabio Maulo

unread,
Jul 24, 2009, 11:29:34 AM7/24/09
to nhu...@googlegroups.com
If you want copy&paste all the code needed is here



--
Fabio Maulo

Fernando Zago

unread,
Jul 24, 2009, 11:35:04 AM7/24/09
to nhu...@googlegroups.com
do i really need .NET Framework 3.5 ?

---
A vida me ensinou a nunca desistir,
nem ganhar, nem perder mas procurar evoluir.
Podem me tirar tudo que tenho!
Só não podem me tirar as coisas boas que eu já fiz pra quem eu amo!
E eu sou feliz e canto e o universo é uma canção eu vou que vou!


Fabio Maulo

unread,
Jul 24, 2009, 1:00:00 PM7/24/09
to nhu...@googlegroups.com
2009/7/24 Fernando Zago <nan...@gmail.com>

do i really need .NET Framework 3.5 ?

To copy&paste ?

--
Fabio Maulo

Fernando Zago

unread,
Jul 24, 2009, 1:55:00 PM7/24/09
to nhu...@googlegroups.com
To Disable Auto Dirty Check!

---
A vida me ensinou a nunca desistir,
nem ganhar, nem perder mas procurar evoluir.
Podem me tirar tudo que tenho!
Só não podem me tirar as coisas boas que eu já fiz pra quem eu amo!
E eu sou feliz e canto e o universo é uma canção eu vou que vou!


Fabio Maulo

unread,
Jul 24, 2009, 2:12:37 PM7/24/09
to nhu...@googlegroups.com
2009/7/24 Fernando Zago <nan...@gmail.com>

To Disable Auto Dirty Check!

No, you don't need NET3.5 (NH2.1.0 is working on .NET2.0)
If you want use existing code (from uNhAddIns) you need .NET3.5.
If you copy&paste the code from uNhAddIns you must modify it for .NET2.0.

--
Fabio Maulo

Fernando Zago

unread,
Jul 24, 2009, 10:34:41 PM7/24/09
to nhu...@googlegroups.com
Fabio, I dont think u are understand what i'm trying to say.

This code that u sayd:

but, this code uses a Extension to make that magic
public static Configuration RegisterDisableAutoDirtyCheckListeners(this Configuration configuration)
{ ... code ... }

My Question:

Do I Really needs to use .NET 3.5 to use this, or
have another way to do that ? Without .net 3.5 ?

---
Vision without action is a waking dream. Action without vision is a nightmare.

Fabio Maulo

unread,
Jul 24, 2009, 10:54:55 PM7/24/09
to nhu...@googlegroups.com
emhhmhmm...
Yes, you can modify that code using .NET2.0 code instead .NET3.5.

2009/7/24 Fernando Zago <nan...@gmail.com>



--
Fabio Maulo

Nelson

unread,
Aug 12, 2009, 1:48:43 PM8/12/09
to nhusers
I got the same problem. NHibernate is flushing the whole first-level
cache while I wanted to update a single entity.
I tried the code available at
http://code.google.com/p/unhaddins/source/browse/#svn/trunk/uNhAddIns/uNhAddIns/Listeners/AutoDirtyCheck
, however it does not work in all cases.

I encountered several problems.

- Only loaded items are marked as ReadOnly. Once they are updated or
if they are inserted their state is Loaded, then they are auto-flushed
again. This problem is fixed by implementing IPostInsertEvent and
IPostUpdateEvent.
- Then if an entity is explicitely SaveOrUpdated, but NHibernate finds
it is not dirty (thank you second level cache?), then its state is set
at Loaded by SaveOrUpdate event listener but is never reversed back
(because it is not inserted nor updated). The solution I found is to
create an interceptor which implements PostFlush() and reverts back
the entity state.
- Finally I bumped into another problem. After looking in
AbstractFlushingEventListener.FlushEverythingToExecutions(FlushEvent
@event), i found this :
....
FlushEntities(@event);
FlushCollections(session);
...
I guess there that any persistent collection is also flushed. If a
persistent collection contains a transient entity, the transient
entity will be added/saved implicitely, even if saveorupdate() has not
be called on the containing entity.
I still haven't found a workaround for this one, if someone has an
idea I'd love to try it.

It took me days to understand my current problems were due to
automatic dirty checking. This implicit behaviour of NHibernate is not
obvious. In my opinion it should be an option disabled by default.

Fabio Maulo

unread,
Aug 13, 2009, 12:55:31 AM8/13/09
to nhu...@googlegroups.com
Test case in uNhAddIns issues tracker, please.
About dirty checking "In my opinion it should be an option disabled by default", thanks for your opinion but it is one of the most useful feature of NHibernate.
If you don't like AutoDirty check and the code in uNhAddIns does not cover exactly what you are looking for you are invited to share your failing test in :

The mailing list is:

Thanks.

2009/8/12 Nelson <nelson...@gmail.com>



--
Fabio Maulo

Nelson

unread,
Aug 13, 2009, 2:42:03 AM8/13/09
to nhusers


On Aug 13, 6:55 am, Fabio Maulo <fabioma...@gmail.com> wrote:
> Test case in uNhAddIns issues tracker, please.About dirty checking "In my
> opinion it should be an option disabled by default", thanks for your opinion

You're welcome. I'm used to try to find an answer before asking
questions, which leads me to having opinions.

> but it is one of the most useful feature of NHibernate.

Thanks for yours. But it is also 'just an opinion', even if said in a
peremptory maneer.

This features leads to unexpected and unobvious behaviour. If you
prefer to have it enabled by default, so be it, but users should
definitely be able to disable it if they want to control nhibernate
update behaviour.
I did not say it is an easy task, but you did not say why it must not
be disabled.

> If you don't like AutoDirty check and the code in uNhAddIns does not cover
> exactly what you are looking for you are invited to share your failing test
> in :http://code.google.com/p/unhaddins/issues/list

Shall I directly post it to NHibernate's JIRA in addition to that?
IT'S A BUG.

Fabio Maulo

unread,
Aug 13, 2009, 8:47:04 AM8/13/09
to nhu...@googlegroups.com
2009/8/13 Nelson <nelson...@gmail.com>


Shall I directly post it to NHibernate's JIRA in addition to that?
IT'S A BUG.

Which is the JIRA ?

--
Fabio Maulo

Stefan Steinegger

unread,
Aug 13, 2009, 10:47:35 AM8/13/09
to nhusers
Nelson, one of NH's benefits is what is called "persistence
ignorance". It means that the business logic does not need to know
about persistence. It just changes the state of the entities (which
are attached to the session), and these changes get persisted
automatically by NH. The business logic does not have to call anything
to make this happen.

The "normal" solution for unexpected updates is: if the business logic
does not want to have something changed, it should not change it.

I know, it is not always that easy. I just try to explain why this is
a reasonable default behavior.

I'm not really sure why you want to have NH reset some of your
changes. It's actually the business logics responsibility to change
the entities as it should be.

Btw, to undo changes made outside of the session (detached), use Get
to get a new instance, or Refresh.

On 13 Aug., 14:47, Fabio Maulo <fabioma...@gmail.com> wrote:
> 2009/8/13 Nelson <nelson.cab...@gmail.com>

Nelson

unread,
Aug 13, 2009, 2:40:25 PM8/13/09
to nhusers
Thank you for taking your time to read and answer this topic.
I do not want NH not to save my changes, I want to control the order
in which NH saves my object graph, so that I can provide feedback to
the user.

Here is a simple test situation.
A entity Parent contains a list of entity Child (Children collection).
I modify the Parent and some Child, but, because each Child is slow to
update, I want to save each Child first, then the Parent. Then I can
provide visual feedback to the user, who can see save progress.
If I call SaveOrUpdate() then Flush() on the child, The first child is
saved, then the parent is flushed and also every child is, in the same
flush.
I was clearing first the session to avoid the problem, but I need then
to reattach my objects, which is pretty awkward. Same thing for
evicting objects.

Finally in my case, iParent is not a single entity but an object graph
and Children are subgraphs of Parent (that is why evicting is not easy
to use). NH throws me exceptions because transient entities are
referenced in a part of the parent graph (auto flush does an Update
not a SaveOrUpdate, and the transient item is a transient entity in an
already loaded persistent collection).

My business logic does not know about how the save is made, I got a
repository for that. Evicting/Clearing session does not make my
business logic more unaware of persistence layer, but cascades do.

People should be able to disable this feature if they want more
control on NH. It should come bundled with NH and not outside of it.
Currently this is not a 'default' behaviour, but the only behaviour.
Reminder :
http://brian.pontarelli.com/2007/04/03/hibernate-pitfalls-part-2/
http://stackoverflow.com/questions/673564/nhibernates-automatic-dirty-checking-update-behaviour-turning-it-off
http://fabiomaulo.blogspot.com/2009/03/ensuring-updates-on-flush.html

I know I need to write a test case. I'll do when I'll have time and
motivation.
Thank you very much for taking some time to answer, Stefan.

On Aug 13, 4:47 pm, Stefan Steinegger <stefan.steineg...@bluewin.ch>
wrote:

Stefan Steinegger

unread,
Aug 14, 2009, 3:27:04 AM8/14/09
to nhusers
I'm still not sure if you aren't using NH for a case it has never been
designed for.

Just to make it clear: every call to NH is not persistence ignorance.
Only calls to the entities are (changing the data).

IMO, it is a very bad idea to change the order how objects get
persisted. In your case, it might work. But actually, the order is
also dictated by foreign key dependencies, and NH tries to store them
in an order where the constraints do not complain.

IMO, it is very bad idea to use evict or another session to store the
changes. You can't just throw half of the objects out of the session,
this couldn't be a consistent state. An object graph should be
persisted in completion, everything else is a hack.

The order of saving usually does not matter for the caller. Even the
point in time when the session is flushed is usually not relevant, and
could be at any time. For instance, Update just puts the object into
the session. Flush is done before queries, to make sure the the data
in the database is up to date.

IMO, it is not worth to touch this vital part of NH. The risk of
making it unstable and putting responsibility back to the caller which
it never had wanted to have, is much to high.

In your case, it is "only" about visual feedback. If your application
gets so slow, you should probably try to solve the performance
problem. If you can't, because you really have to update thousands of
records, you probably need this visual feedback.

I think I would use NH events or Interceptors to implement the visual
feedback. For instance, you can try to find out the number of dirty
entities and then count the number of update calls to the interceptor
or the event. This would be very nice anyway, because you can have
visual feedback on every call to the database without messing around
with the session.

I can't tell you exactly how this should be implemented.
> Reminder :http://brian.pontarelli.com/2007/04/03/hibernate-pitfalls-part-2/http://stackoverflow.com/questions/673564/nhibernates-automatic-dirty...http://fabiomaulo.blogspot.com/2009/03/ensuring-updates-on-flush.html

mipi

unread,
Aug 14, 2009, 3:30:12 AM8/14/09
to nhusers
My first message here, so hello :) I am very new to NHibernate, but I
like it already.

> The "normal" solution for unexpected updates is: if the business logic
> does not want to have something changed, it should not change it.

I have a question what is the "NHibernate way" of doing this simple
task?
I've slightly modified the example from the documentation.

sess = sf.OpenSession();
ITransaction tx = sess.BeginTransaction();
Cat izi = (Cat) sess.Load(typeof(Cat), id);

izi.Name = "iznizi#$%^@*";

if (izi.IsValid())
// persist it here

tx.Commit();

Stefan Steinegger

unread,
Aug 14, 2009, 8:00:23 AM8/14/09
to nhusers
You should create new post to ask a new question.

There is not actually a NH way, but a "transactional way" is to either
commit the changes or rollback the whole thing. This is usually done
by exception handling.

Just an example in pseudo code:

try
{
cat = Load(id);
cat.Name = "some name";
Validate(cat); // throws exception
session.Commit();
}
catch
{
session.Rollback();

vitalya

unread,
Aug 14, 2009, 8:03:33 AM8/14/09
to nhusers
Hi everyone,
Recently i've also faced similar problem. First i've posted a <a
href="http://groups.google.com/group/castle-project-users/
browse_thread/thread/f2fc359da7228fca?hl=en"> question</a> to
castleproject-users group, but than after deeper investigation it
turned out to be the NHibernate behavior.
I'm working in the web context, so my scenario is the following:
1. Get entity from repository by Id
2. Bind simple properties (like string, integers etc.)
3. Bind Many-to-one properties (like User.Country)
4. If binded entity is valid - persist changes, otherwise show
validation erros and DO NOT SAVE invalid dirty entity.

With default auto-flushing dirty objects behavior i get the following
problems:
1. During the step3 i have to query database to get entities
references as many-to-one. Sometimes Session.Load is not suitable and
i have to query database, that causes unwanted flushing.
2. During validation i also might need to query database (to check
Unique constraints), than also causes unwanted flushing.

Currently i see few possible ways, but they are not brilliant:
1. Use FlushMode.Commit. The disadvantage here is that during
executing select statements the result won't be relevant, because
valid not flushed changes to the entities won't be taken into account.
2. Forget about persistence ignorance and use evict and attach to
session approach within business logic code
3. First bind to in-memory DTO, check if data is valid and only then
map changes to the real entity. But this approach will produce a lot
of extra code and bugs.

If there are no other ways i'm going to choose manual Evicting.
Am i missing something?
Thanks for your help

Stefan Steinegger

unread,
Aug 14, 2009, 8:58:25 AM8/14/09
to nhusers
I wouldn't evict anything. Just my opinion.

There is no persistence ignorance if you can tell the persistence
layer to undo some changes in memory. If you implement as if there is
no persistency, you don't expect to be able to undo a few changes you
made in memory. There aren't "two layers" of changing data. So if you
change anything in memory, the changes is already done. There are
always two options: Commit or Rollback the whole stuff.

So my suggestion is: implement as if there wasn't a database. Rely on
transactions, they are important, to make it atomic (all or nothing).
Don't think in doing stuff in memory first and then choosing what,
when and how to write it into the database.

vitalya

unread,
Aug 14, 2009, 9:57:19 AM8/14/09
to nhusers
Ok, it sounds reasonable. But where validation that requires database
query should be placed?. Should it go before business operation, that
changes entity state? Pre-validation also would cause bugs, especially
in case of complex business rules.

On Aug 14, 3:58 pm, Stefan Steinegger <stefan.steineg...@bluewin.ch>
wrote:

kurtharriger

unread,
Aug 22, 2009, 12:39:32 AM8/22/09
to nhusers
I also would like to go on the record as saying that I too believe
dirty checking is a a bad idea and probably should be considered a bug
because it violates encapsulation boundaries. The leakage of mutable
references makes it difficult to verify that business rules always
remain valid when changes are persisted. You can read more on my blog
here:

http://kurtharriger.wordpress.com/2009/08/21/how-nhibernates-dirty-checking-violates-encapsulation-boundries/


On Aug 13, 12:42 am, Nelson <nelson.cab...@gmail.com> wrote:
> On Aug 13, 6:55 am, Fabio Maulo <fabioma...@gmail.com> wrote:
>
> > Test case in uNhAddIns issues tracker, please.Aboutdirtychecking "In my

Oskar Berggren

unread,
Aug 24, 2009, 2:52:18 AM8/24/09
to nhu...@googlegroups.com
2009/8/22 kurtharriger <kurtha...@gmail.com>:
>
> I also would like to go on the record as saying that I too believe
> dirty checking is a a bad idea and probably should be considered a bug
> because it violates encapsulation boundaries.

I disagree with your terminology. I consider a bug to be a "violation
of specification or intended behaviour". Auto dirty checking is
intended. What we have here I would call a feature request, since the
ability to completely turn of auto dirty checking would be a new
feature.


> The leakage of mutable
> references makes it difficult to verify that business rules always
> remain valid when changes are persisted.  You can read more on my blog
> here:
>
> http://kurtharriger.wordpress.com/2009/08/21/how-nhibernates-dirty-checking-violates-encapsulation-boundries/


I too have at times pondered whether dirty checking is good or bad.
However, some comments on your article:

You make the example of trying to add to lineitems, first succeeds,
second fails, but then one is persisted anyway. You state the solution
to this yourself: Rollback the transaction. I don't see how this would
logically couple your application to NHibernate, since transactions is
a much more general concept and not something that NHibernate
introduces. I think the rule is quite simple: "If there is an
exception in you UoW, then the associated transaction should/must be
aborted."


But like I said, I have also struggled with how to enforce validation
before commit. This should probably be done by using NHibernate's
event system, to let NHhibernate call you validation logic right
before updating the database. Have you looked into this?


Also, have you considered the alternative? I mean some kind of manual
keeping-track-of-stuff-that-must-be-updated? What problems would be
associated with that?

/Oskar

Stefan Steinegger

unread,
Aug 24, 2009, 4:41:24 AM8/24/09
to nhusers
I try to explain it again.

Don't rely on the fact that there is a database. Validation should not
occur before changes are persisted, but when they are done (in memory,
by the business logic).

Making changes in memory but not storing them is NOT the solution. How
would to reliably validate entities if you have invalid data in
memory? How would you calculate the price of an order when you allow
any part of the software changing the price of a product in memory?
Your memory needs to be as consistent as the database.

Automatic dirty checking means, that all changes will be persisted. It
is a problem of your application if you don't know which part of the
application changes which entities and therefore you don't know where
to put validation logic.

By the way, to prevent others to perform changes on entities they
shouldn't, you can implement immutable interfaces which only consist
of references to others by immutable interfaces. the problem here is,
that C# does not have the const keyword as C has. This is missed in
many places which is also not related to NH.

When working with DTO's (what most people in large projects do), this
is not an issue anyway. You'll have a "SafeProduct" method, which
takes a DTO as argument. This method applies only the values that are
changeable to the entities, and validates it.

There is a feature by NH that allows validation within the entity at
the point in time before it gets persisted. Just implement the
interface IValidatable
(see http://knol.google.com/k/fabio-maulo/nhibernate-chapter-4/1nr4enxv3dpeq/7#4%282E%295%282E%29%28C2%29%28A0%29IValidatable_callback).
(This is of course only meaningful for validation within the
aggregation boundary.)

If your application depends on an existing dirty check mechanism, you
could write an interceptor which calls it.
http://www.surcombe.com/nhibernate-1.2/api/html/M_NHibernate_IInterceptor_FindDirty.htm

You could also validate in a OnFlushDirty: check all the entities
which are going to be stored, and throw an exception if they shouldn't
change. It would be a programming error. Not sure if this is worth the
effort.


On 24 Aug., 08:52, Oskar Berggren <oskar.bergg...@gmail.com> wrote:
> 2009/8/22 kurtharriger <kurtharri...@gmail.com>:
>
>
>
> > I also would like to go on the record as saying that I too believe
> > dirty checking is a a bad idea and probably should be considered a bug
> > because it violates encapsulation boundaries.
>
> I disagree with your terminology. I consider a bug to be a "violation
> of specification or intended behaviour". Auto dirty checking is
> intended. What we have here I would call a feature request, since the
> ability to completely turn of auto dirty checking would be a new
> feature.
>
> > The leakage of mutable
> > references makes it difficult to verify that business rules always
> > remain valid when changes are persisted.  You can read more on my blog
> > here:
>
> >http://kurtharriger.wordpress.com/2009/08/21/how-nhibernates-dirty-ch...

Fabio Maulo

unread,
Aug 24, 2009, 10:03:51 AM8/24/09
to nhu...@googlegroups.com
I don't understand if you are joking or what.

You can disable autodirty check by configuration.

Using similar events of NHV
you can prevent flush of invalid entities.

If your concept of "incapsulation" mean have all under your control in a single place what you are looking for is this



--
Fabio Maulo
Reply all
Reply to author
Forward
0 new messages