-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 12 posts ] 
Author Message
 Post subject: Dirty checking of a property
PostPosted: Sun Jan 18, 2009 3:12 am 
Newbie

Joined: Sun Jan 18, 2009 3:03 am
Posts: 3
I'm using hibernate 3+ along with spring. I've implemented OpenSessionInViewFilter, so that the session is closed at the time of completion of request. I need to perform some business logic if a property value changes for an entity. When I do session.get, I do not get the snapshot of the entity from the database but the one which is currently available in the session and modified by view.

Is there a way in hibernate to get the current database snapshot of entity or to find out if a property is dirty using API?


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jan 18, 2009 5:17 am 
Senior
Senior

Joined: Thu Jan 08, 2009 3:48 pm
Posts: 168
Just do a HQL or Criteria Query, then it should get the value from the database.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jan 18, 2009 5:43 am 
Newbie

Joined: Sun Jan 18, 2009 3:03 am
Posts: 3
Even the criteria query made on id field results in the same object from the session.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jan 18, 2009 10:26 am 
Senior
Senior

Joined: Thu Jan 08, 2009 3:48 pm
Posts: 168
Shouldn't, and i'm pretty sure if you try it out with SQL Log enabled you see the SELECT go to the database.
Unless the query cache is enabled (which isn't by default) Hibernate can not know the result of a query beforehand.
If it returns the same value maybe it was already updated in the database?


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jan 18, 2009 2:35 pm 
Expert
Expert

Joined: Wed Mar 03, 2004 6:35 am
Posts: 1240
Location: Lund, Sweden
There are several problems with this approach:

1. Hibernate usually flushes changes made to entities to the database before a HQL or criteria query is executed. To change this you'll have to set the flush mode to for example FlushMode.COMMIT.

2. A single session can only hold one object representing the same row in the database. So, since the modified object is already associated with the session you will always get the same instance back from session.get(), HQL and criteria queries, etc.

There are some possible ways to find out what is actually in the database:

1. Open a second session and re-load the entity with the new session.
2. Use a scalar query to get the information in the database as an Object[]
3. evict() the entity from the session and re-load it from the database. But then you'll have the problem to get the updates back into the database.

I wouldn't recommend any of the above though, since there is always the risk that another transaction has updated the database and then you are seeing a difference even if the entity has not been updated.

It may be a better approach to register an Interceptor with Hibernate and for example, implement the onFlushDirty() method which is called by Hibernate when an entity has been detected as dirty (=modified).


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jan 19, 2009 2:56 am 
Senior
Senior

Joined: Thu Jan 08, 2009 3:48 pm
Posts: 168
nordborg wrote:
2. A single session can only hold one object representing the same row in the database. So, since the modified object is already associated with the session you will always get the same instance back from session.get(), HQL and criteria queries, etc.

I tried that out locally, load()+access to property results in a select, get() in the same session afterwards doesn't.
But any type of query does result in a new select to the database.

Please explain if you mean something different...


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jan 19, 2009 3:10 am 
Expert
Expert

Joined: Wed Mar 03, 2004 6:35 am
Posts: 1240
Location: Lund, Sweden
It doesn't matter if there is a select in the database or not. As long as the row is already represented with an object in the current session (eg. the object that you have already updated) you will get the same object back. It is explained here:

http://www.hibernate.org/hib_docs/v3/re ... s-identity


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jan 19, 2009 5:01 am 
Newbie

Joined: Sun Jan 18, 2009 3:03 am
Posts: 3
The simplest thing I found was to use another session to get object by id. it gives me the current record from database. Since, the second retrieval is read only and concurrency is controlled by database, it serves my purpose. Thanks guys for all your help


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jan 19, 2009 5:22 pm 
Senior
Senior

Joined: Thu Jan 08, 2009 3:48 pm
Posts: 168
nordborg wrote:
It doesn't matter if there is a select in the database or not. As long as the row is already represented with an object in the current session (eg. the object that you have already updated) you will get the same object back. It is explained here:

http://www.hibernate.org/hib_docs/v3/re ... s-identity


Thanks nordborg, i it tried it out, good thing i know now that you were right.
Would have been bad to base assumptions on such things in the future...

Thumbs up because i can't rate here ;o)


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jan 19, 2009 6:19 pm 
Senior
Senior

Joined: Thu Jan 08, 2009 3:48 pm
Posts: 168
nordborg wrote:
...


Just tried out session.refresh(object)
This makes the current session aware of changes to the database:

Code:
User user4 = (User) session.get(User.class, 8);
System.out.println("Username: " + user4.getUsername());

System.out.println("Press key to continue...");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String s = br.readLine();

session.refresh(user4);
System.out.println("Username: " + user4.getUsername());


Output after updating username to 'quaqua' while program waited for user input:
Code:
Hibernate: select user0_.ID as ID0_0_, user0_.username as username0_0_, user0_.password as password0_0_, user0_.title as title0_0_, user0_.firstname as firstname0_0_, user0_.lastname as lastname0_0_, user0_.email as email0_0_, user0_.account_id as account8_0_0_ from USERS user0_ where user0_.ID=?
Username: user1
Press key to continue...

Hibernate: select user0_.ID as ID0_1_, user0_.username as username0_1_, user0_.password as password0_1_, user0_.title as title0_1_, user0_.firstname as firstname0_1_, user0_.lastname as lastname0_1_, user0_.email as email0_1_, user0_.account_id as account8_0_1_, products1_.user_id as user1_3_, product2_.ID as product2_3_, product2_.ID as ID3_0_, product2_.name as name3_0_, product2_.price as price3_0_ from USERS user0_ left outer join USER_PRODUCTS products1_ on user0_.ID=products1_.user_id left outer join PRODUCTS product2_ on products1_.product_Id=product2_.ID where user0_.ID=?
Username: quaqua


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jan 19, 2009 6:35 pm 
Expert
Expert

Joined: Wed Mar 03, 2004 6:35 am
Posts: 1240
Location: Lund, Sweden
Quote:
Just tried out session.refresh(object)
This makes the current session aware of changes to the database:


Yes it does, but it will overwrite changes made to the object that is currently associated with the session and changes made to it will be lost. If I understood the original post correctly this was not desired.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jan 19, 2009 6:50 pm 
Senior
Senior

Joined: Thu Jan 08, 2009 3:48 pm
Posts: 168
Yeah you're right :o)

Tried your suggestion with the scalar query
Code:
String u = (String)session.createQuery("select username from User where id = :id").setLong("id",8).uniqueResult();


This works fine, only the String contains the new value from the database, the object in the session is left untouched.

Thanks for the lesson


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 12 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.