-->
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.  [ 10 posts ] 
Author Message
 Post subject: OnUpdate doesn't always fire
PostPosted: Thu Sep 27, 2007 9:01 am 
Beginner
Beginner

Joined: Wed Aug 01, 2007 4:28 pm
Posts: 23
I'm sure this has been discussed, but why is the behavior of the ILifeCycle OnUpdate method so strange? I noticed it wasn't firing in my classes, and after digging thru the documentation, i found that OnUpdate only fires when transient objects are updated. Why is this the case? Is it a bug? Wouldn't most developers assume (and desire) onUpdate to fire on every update to the database.

Thanks,
Craig


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 28, 2007 11:42 am 
Beginner
Beginner

Joined: Wed Aug 01, 2007 4:28 pm
Posts: 23
Does anyone have any ideas on this? I'm really stuck. how do people do things like update a "DateUpdated" field thru the business objects when this method doesn't fire consistently?

Thanks,
Craig


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 28, 2007 6:57 pm 
Hibernate Team
Hibernate Team

Joined: Tue Jun 13, 2006 11:29 pm
Posts: 315
Location: Calgary, Alberta, Canada
Supposedly, OnUpdate() fires when you update an entity that was pulled from the database through NHibernate. OnSave() fires when you save/insert an entity that is totally new.

In other words, if you do the following, OnUpdate() should fire:
Code:
Person person = session.Get<Person>(id);
// Change something about person
session.Update(person);
// OnUpdate() should fire when the changes are pushed back to the database

The following should cause OnSave() to fire, but not OnUpdate():
Code:
Person person = new Person();
// Change something about person
session.Save(person);
// OnSave() should fire when the Person is inserted to the database

_________________
Karl Chu


Top
 Profile  
 
 Post subject:
PostPosted: Sat Sep 29, 2007 4:13 am 
Contributor
Contributor

Joined: Wed May 11, 2005 4:59 pm
Posts: 1766
Location: Prague, Czech Republic
Don't use ILifecycle, it's deprecated. Use IInterceptor.

The reason ILifecycle.OnUpdate is called at a strange time is in the name of the interface - it's about the object life cycle. Lifecycle methods get called when an object changes its state (from transient to persistent, from detached to persistent, from persistent to transient).


Top
 Profile  
 
 Post subject:
PostPosted: Mon Oct 01, 2007 11:21 am 
Beginner
Beginner

Joined: Wed Aug 01, 2007 4:28 pm
Posts: 23
karlchu,

I assumed the same thing but apparently thats not the case.

sergey,

I guess that makes sense in a a way... Not sure what the practical benefit would be of only responding to the object's lifecycle seperate from the database.

I tried IInterceptor, but my main problem with it is that i can't seem to update the entity directly...it looks as if have to loop thru the object array of the entity's state and update those the primitive values. Then the object would have a different state from what was in the database. Is this correct?

This is doesn't seem very OO and seems error prone and more difficult. I tried just casting the entity and making my changes directly to it but they didn't make it to the database. I guess i could make it work or create some kind of wrapper around it...

Am I doing something wrong? Thanks for your help!
Craig


Top
 Profile  
 
 Post subject:
PostPosted: Mon Oct 01, 2007 12:13 pm 
Hibernate Team
Hibernate Team

Joined: Tue Jun 13, 2006 11:29 pm
Posts: 315
Location: Calgary, Alberta, Canada
Here is my interceptor, adapt for your own need:
Code:
   public class PersistenceInterceptor : NHibernate.EmptyInterceptor
   {
      public override bool OnSave(object entity, object id, object[] state, string[] propertyNames, NHibernate.Type.IType[] types)
      {
         // This method is called when a new entity is saved.
         // When updating, this is not called.

         bool stateChanged = false;

         if (entity is ICreationLogged)
         {
            bool iCreationLoggedPropertiesChanged = UpdateICreationLoggedProperties(state, propertyNames);
            stateChanged = stateChanged || iCreationLoggedPropertiesChanged;
         }
         if (entity is ILastUpdateLogged)
         {
            bool iLastUpdateLoggedPropertiesChanged = UpdateILastUpdateLoggedProperties(state, propertyNames);
            stateChanged = stateChanged || iLastUpdateLoggedPropertiesChanged;
         }

         return stateChanged;
      }

      private bool UpdateICreationLoggedProperties(object[] state, string[] propertyNames)
      {
         bool stateChanged = false;

         for (int i = 0; i < propertyNames.Length; i++)
         {
            if ("CreateDateTime".Equals(propertyNames[i]))
            {
               state[i] = DateTime.Now;
               stateChanged = true;
            }
            else if ("CreateUserId".Equals(propertyNames[i]))
            {
               if (ThreadLocalData.Instance.UserSession != null)
               {
                  state[i] = ThreadLocalData.Instance.UserSession.UserId;
                  stateChanged = true;
               }
            }
         }

         return stateChanged;
      }

      public override bool OnFlushDirty(object entity, object id, object[] currentState, object[] previousState, string[] propertyNames, NHibernate.Type.IType[] types)
      {
         // This method is called when an entity is updated.

         bool stateChanged = false;

         if (entity is ILastUpdateLogged)
         {
            stateChanged = UpdateILastUpdateLoggedProperties(currentState, propertyNames);
         }

         return stateChanged;
      }

      private bool UpdateILastUpdateLoggedProperties(object[] currentState, string[] propertyNames)
      {
         bool stateChanged = false;

         for (int i = 0; i < propertyNames.Length; i++)
         {
            if ("LastUpdateUserId".Equals(propertyNames[i]))
            {
               if (ThreadLocalData.Instance.UserSession != null)
               {
                  int? userId = ThreadLocalData.Instance.UserSession.UserId;
                  if (!Nullable<int>.Equals(currentState[i], userId))
                  {
                     currentState[i] = userId;
                     stateChanged = true;
                  }
               }
            }
            else if ("LastUpdateDateTime".Equals(propertyNames[i]))
            {
               DateTime? dateTime = DateTime.Now;
               if (!Nullable<DateTime>.Equals(currentState[i], dateTime))
               {
                  currentState[i] = dateTime;
                  stateChanged = true;
               }
            }
         }

         return stateChanged;
      }
   }

_________________
Karl Chu


Top
 Profile  
 
 Post subject:
PostPosted: Mon Oct 01, 2007 2:25 pm 
Beginner
Beginner

Joined: Wed Aug 01, 2007 4:28 pm
Posts: 23
Wouldn't these get called every time ANY class is saved/updated, etc?

I think i can use this, but i'm just surprised that the NHibernte team hasn't come up with something more straightfoward to do something that is very common: update the object before it is persisted to set things like DateUpdated fields, history related to that object, etc.

Wilson's ORM has an interface for just these things and its very easy.

-Craig


Top
 Profile  
 
 Post subject:
PostPosted: Mon Oct 01, 2007 4:12 pm 
Hibernate Team
Hibernate Team

Joined: Tue Jun 13, 2006 11:29 pm
Posts: 315
Location: Calgary, Alberta, Canada
Nothing is perfect, and everything is a trade-off. Pick your poison. ;-)

_________________
Karl Chu


Top
 Profile  
 
 Post subject:
PostPosted: Mon Oct 01, 2007 4:17 pm 
Beginner
Beginner

Joined: Wed Aug 01, 2007 4:28 pm
Posts: 23
Well thats true enough. It just seems like this would be a very common requirement for a lot of apps.

So was I right that updating the entity does not work? You have to loop thru the property name/values like you''re doing? Also, once you do that, does Nhibernate update the object in memory as well?

Craig


Top
 Profile  
 
 Post subject:
PostPosted: Mon Oct 01, 2007 4:33 pm 
Hibernate Team
Hibernate Team

Joined: Tue Jun 13, 2006 11:29 pm
Posts: 315
Location: Calgary, Alberta, Canada
fregas wrote:
So was I right that updating the entity does not work? You have to loop thru the property name/values like you''re doing?

You are right, updating "entity" does not work... at least that was the case in the alpha version of 1.2. That's when I wrote this Interceptor.

fregas wrote:
Also, once you do that, does Nhibernate update the object in memory as well?

I am under the impression that NH does update the object in memory. I don't know for sure as it was never an issue for me. It would be easy enough to find out quickly in a debugging session though.

_________________
Karl Chu


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