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.  [ 8 posts ] 
Author Message
 Post subject: Bug?
PostPosted: Fri Dec 29, 2006 8:36 pm 
Newbie

Joined: Thu Jan 12, 2006 8:17 am
Posts: 8
I have an object I´m trying to save that has a DateTime property.
If I leave the property to DateTime.MinValue SQL Server 2005 gives me an error, so I did the following code in the Save method of my program:
Code:
foreach (PropertyInfo pi in objectToSave.GetType().GetProperties()) {
  if (pi.PropertyType == typeof(DateTime)) {
    if (((DateTime)pi.GetValue(objectToSave, null)) == DateTime.MinValue) {
      pi.SetValue(objectToSave, DateHelper.MinValue, null);
    }
  }
}


This way I assure that no DateTime properties that are currently null will get saved as DateTime.MinValue in the database. I did the opposite in the Load method, so it sets the property do DateTime.MinValue in case the database returns the DateHelper.MinValue property value.

This works well until I have the following situation:

BeginTrans();
object id = Save(project);
Project proj = Load(id);
Commit();

The problem here is when I Save the object it has DateHelper.MinValue for all date properties. This works perfectly if I comment the load line (the object gets saved perfectly).
But if I load the same Id from the database in the same transaction the object (another instance if you look at the code above) has the DateTime properties set again to DateTime.MinValue (desired behavior).
By the time I commit it gives me an error of Date must be higher than ....

What I mean is: If I load a not-commited object from the database and modify it in memory, by the time I commit the whole transaction the object that will be saved is the loaded one? Shouldn´t the object being saved be the one from the save line?!

Maybe I am missing something here, but I don´t think I am.

Thanks anyway,

Bernardo Heynemann


Top
 Profile  
 
 Post subject:
PostPosted: Sat Dec 30, 2006 1:15 am 
Regular
Regular

Joined: Tue Feb 21, 2006 9:50 am
Posts: 107
Your problem is the SQL Server. DateTime.MinValue evaluates to 01.01.0001. The smallest possible date for the SQL Server is 01.01.1701 by default.

Regards
Klaus


Top
 Profile  
 
 Post subject:
PostPosted: Sat Dec 30, 2006 8:56 am 
Contributor
Contributor

Joined: Sat Sep 24, 2005 11:25 am
Posts: 198
Use DateTime? (nullable datatime) to make it work.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Dec 30, 2006 11:27 am 
Newbie

Joined: Thu Jan 12, 2006 8:17 am
Posts: 8
You guys missed my point.
I know that if I use DateTime? it will work.
What I´m not getting is the flow of actions that NHibernate is taking.

This is what I´m doing:

1) Create a new instance of the object (with the date property set to null).
2) Call my Save method that, by reflection, sets all the DateTime properties that have null values to DateHelper.MinValue (01/01/1800 00:00:00).
3) Call the ISession.Save() method passing in my object (that now has valid dates).
4) Call the ISession.Get<>() method to get the same object that I just saved.
5) After getting the object my Load method sets all the DateTime properties that have DateHelper.MinValue values to DateTime.MinValue (by reflection).
6) Commit the transaction.

If I skip steps 4 and 5, everything works like a charm.
So my question is: if I change an object after calling Save, when I commit it these changes will persist? And if I save one object and load another one with the same Id NHibernate uses the same instance?

Thanks for the help,
Bernardo Heynemann


Top
 Profile  
 
 Post subject:
PostPosted: Sat Dec 30, 2006 11:44 am 
Expert
Expert

Joined: Tue Aug 23, 2005 5:52 am
Posts: 335
Yes, they will be persisted. This is by design, although this is often a confusing subject for newbies. You may want to read up one something called Transparent Persistence.

Any object that is a member of an NHibernate session (ie, which has been saved to the session using ISession.Save, loaded into the session using ISession.Load, ISession.Get or as the result of some other query, or reconnected to the session using ISession.Update, ISession.Lock, etc) will have any changes transparently persisted to the database when the session is flushed.

Session flushing happens automatically when a transaction is committed or the session is closed (by default). You can change the FlushMode of the session to alter when it will be flushed, but if you commit a transaction it will have to flush to make sure the content of the database contains the state of the objects that were changed in memory.

If you want to modify objects and not have their state flushed you can always evict them from the session using ISession.Evict before the session flushes.

Hope that helps.

Cheers,

Symon.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Dec 30, 2006 11:56 am 
Newbie

Joined: Thu Jan 12, 2006 8:17 am
Posts: 8
I placed Evict calls after the Save method.
But once I load the object, they get in the session again, and are saved once I commit.

Very odd behavior in my opinion.

I want changes to be persisted when I call Save, otherwise there´s no meaning to call Save... I just load the object change whatever I want and call Commit.

There´s a way to override this behavior?

Bernardo Heynemann


Top
 Profile  
 
 Post subject:
PostPosted: Sat Dec 30, 2006 12:12 pm 
Contributor
Contributor

Joined: Sat Sep 24, 2005 11:25 am
Posts: 198
No, there is no way to override this behavior , this is a core part of the way NHibernate is operating.
Please read a bit about Unit Of Work to understand what it is doing.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 03, 2007 1:03 pm 
Expert
Expert

Joined: Tue Aug 23, 2005 5:52 am
Posts: 335
I think the confusion here comes from your understanding of what the Save() method actually implies.

Personally, when I began I found the names of the methods Save(), Update() and Delete() very confusing because I thought they would explicitly perform actions on the database - they don't; they simply perform actons on the *persistent state* of the object.

The idea is that initially your object, when instantiated for the first time, is not a persistent object. Once you call Save() you're asking NHibernate to treat the object as persistent and handle putting the information into and getting the information out of the database for you.

When you load an object from the database it's state is clearly already persistent, otherwise it woulnd't be in the database. As a result, the object that is instantiated in memory is still a persistent object and any changes are automatically tracked for you and updated to the database (on flush, which normally happens on commit as mentioned in my previous post).

There are two things you can do to make the current instance in memory non-persistent:

1. Temporarily prevent changes to the object's state from being persisted by evicting the *instance* from the session using Evict(). The object is still in the database in the same state from which you loaded it, so if you load it again it will be the same as before.

2. Permanently remove the objects persistent data from the database by calling Delete(). This will leave you with the loaded object in memory, but the underlying data in the database will be gone and the object will not longer be persisted. You could re-perisist it by calling Save() again, but you'd possibly end up with a new identifier for the object.

Does that help clarify things a bit?

Cheers,

Symon.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 8 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.