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.  [ 6 posts ] 
Author Message
 Post subject: Problem with "OnUpdate" Event
PostPosted: Mon Feb 13, 2006 7:18 am 
Newbie

Joined: Mon Feb 13, 2006 6:49 am
Posts: 2
Hibernate version: 1.0.2

Mapping documents:

code

Code:
   public class SubscriptionParameter : ILifecycle
   {
      private Subscription subscription;
      private TopicParameter topicParameter;
      private String value;

      public TopicParameter TopicParameter
      {
         get { return topicParameter; }
         set { topicParameter = value; }
      }


      public string Value
      {
         get { return this.value; }
         set { this.value = value; }
      }

      [XmlIgnore]
      public Subscription Subscription
      {
         get { return subscription; }
         set { subscription = value; }
      }

      public LifecycleVeto OnSave(ISession s)
      {
         //Do something
         return LifecycleVeto.NoVeto;
      }

      public LifecycleVeto OnUpdate(ISession s)
      {
         //Do something
         return LifecycleVeto.NoVeto;
      }

      public LifecycleVeto OnDelete(ISession s)
      {
         //Do something
         return LifecycleVeto.NoVeto;
      }

      public void OnLoad(ISession s, object id)
      {
      }
   }


mapping

Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
    <class name="Ft.NotificationService.Business.Entity.SubscriptionParameter, Ft.NotificationService.Business" table="SubscriptionParameter" lazy="false">
      <composite-id>
         <key-many-to-one name="TopicParameter" column="TopicParameterId"/>
         <key-many-to-one name="Subscription" column="SubscriptionId"/>
      </composite-id>      
         
      <property name="Value" not-null="true" type="AnsiString" length="9000"/>      
   </class>
</hibernate-mapping>


Code between sessionFactory.openSession() and session.close():

Code:
         ISession session = null;
         ITransaction transaction = null;

         session = sessionFactory.openSession();
         transaction = session.BeginTransaction();

         SubscriberManager subscriberManager = SubscriberManager.GetInstance();
         Subscriber subscriber = subscriberManager.FindById(53, session);

         TopicManager topicManager = TopicManager.GetInstance();
         Topic topic = topicManager.FindByAlias("CARDNOTIFICATIONS", session);

         SubscriptionManager subscriptionManager = SubscriptionManager.GetInstance();
         Subscription subscription = new Subscription();
           
         TopicParameterManager topicParameterManager = TopicParameterManager.GetInstance();
         TopicParameter topicParameter = topicParameterManager.FindByAliasAndTopicAlias("CARDNUMBER", "CARDACCOUNTNOTIFICATIONS", session);

         subscription.WasLastInvokeSuccesfull = DBNull.Value;
         subscription.Topic = topic;
         subscription.Subscriber = subscriber;
         subscription.LastInvokeTime = DBNull.Value;
         subscription.IsStopped = false;
         subscription.IsDeleted = false;

         session.Save(subscription);

         SubscriptionParameter subscriptionParameter = new SubscriptionParameter();
         subscriptionParameter.Value = "val";
         subscriptionParameter.TopicParameter = topicParameter;
         subscriptionParameter.Subscription = subscription;

         session.Save(subscriptionParameter);

         subscriptionParameter.Value = "val1";
         session.Update(subscriptionParameter);

         transaction.Commit();
         session.Close();
         Console.ReadLine();



Name and version of the database you are using: MS SQL Server 2000

Hi all!
A have been confronted with the following problem: I have an object implementing ILifecycle. So, I need to make 3 handlers for 3 events (Save, Delete and Update). How it's written in NHibernate documentation, that ILifecycle Methods OnSave, OnUpdate and OnDelete methods will be called, when that events occurs. OnSave and OnDelete are OK, but there are mistake when Update happens, and OnUpdate method is not called!
Next thing, I've taken NHibernate sources and begin to look what's happening there. And I found next code:


Code:
         CheckIsOpen();

         if( obj == null )
         {
            throw new ArgumentNullException( "obj", "attempted to update null" );
         }

         if( ReassociateIfUninitializedProxy( obj ) )
         {
            return;
         }

         object theObj = UnproxyAndReassociate( obj );

         IClassPersister persister = GetPersister( theObj );

         if( IsEntryFor( theObj ) )
         {
            [b]//here we have a problem: we should envoke onUpdate method, but we do not envoke anything, the fact that object implements ILifecycle is simply ignored.[/b]
            log.Debug( "object already associated with session" );
            // do nothing
         }
         else
         {
            // the object is transient
            object id = persister.GetIdentifier( theObj );

            if( id == null )
            {
               // assume this is a newly instantiated transient object
               throw new HibernateException( "The given object has a null identifier property " + MessageHelper.InfoString( persister ) );
            }
            else
            {
               DoUpdate( theObj, id, persister );
            }
         }

it's Impl/SessionImpl.cs line 1462
my solution was the simpliest thing I could thought out - I have written the following:

Code:
         if( IsEntryFor( theObj ) )
         {
            object id = persister.GetIdentifier( theObj );

            if( id == null )
            {
               // assume this is a newly instantiated transient object
               throw new HibernateException( "The given object has a null identifier property " + MessageHelper.InfoString( persister ) );
            }

            if( persister.ImplementsLifecycle )
            {
               log.Debug( "calling onUpdate()" );
               if( ( ( ILifecycle ) obj ).OnUpdate( this ) == LifecycleVeto.Veto )
               {
                  log.Debug( "update vetoed by onUpdate()" );
                  Reassociate( obj, id, persister );
                  return;
               }
            }
            
            log.Debug( "object already associated with session" );
            // do nothing
         }


May be it's stupid, but I really cant understand all the logic of NHibernate in several hours to write something more complicated. I hope the developers will fix that problem as it should be in next version!
Sorry for awful english!


Top
 Profile  
 
 Post subject: Works as documented
PostPosted: Mon Feb 13, 2006 8:03 am 
Regular
Regular

Joined: Tue Jan 03, 2006 7:21 am
Posts: 85
I would say that in this case it is working as documented. The documentation says:

Note that onUpdate() is not called every time the object's persistent state is updated. It is called only when a transient object is passed to Session.update().

The reason it is not calling OnUpdate is because you are passing an Object that is already associated with a session. OnUpdate will be called if you pass a transient Object to Save (as in seen in the else part)

Code:
if( IsEntryFor( theObj ) )
         {
            [b]//here we have a problem: we should envoke onUpdate method, but we do not envoke anything, the fact that object implements ILifecycle is simply ignored.[/b]
            log.Debug( "object already associated with session" );
            // do nothing
         }
         else
         {
            // the object is transient
            object id = persister.GetIdentifier( theObj );

            if( id == null )
            {
               // assume this is a newly instantiated transient object
               throw new HibernateException( "The given object has a null identifier property " + MessageHelper.InfoString( persister ) );
            }
            else
            {
               DoUpdate( theObj, id, persister );
            }
         }


Top
 Profile  
 
 Post subject:
PostPosted: Tue Feb 14, 2006 1:16 am 
Newbie

Joined: Mon Feb 13, 2006 6:49 am
Posts: 2
Quote:
The reason it is not calling OnUpdate is because you are passing an Object that is already associated with a session. OnUpdate will be called if you pass a transient Object to Save (as in seen in the else part)


So, I can understand that the object which is associated with a session will never call OnUpdate, and it's normal NHibernate logic.

OK, but I want to ask some more:
I have the following situation: my program should make some operations when the Value field of SubscriptionParameter is Updated and posted to DB. It there any way to handle this event using the features of NHibernate, some other mechanism of event handling, which can provide more functionality?
The thing is that I'm trying to make more complex mechanism, which will include not only this event, but number of events related to different entities which will be connected with them dinamically.
Is it possible to handle all Update events using some other NHibernate feature?


Top
 Profile  
 
 Post subject: Custom UserType
PostPosted: Tue Feb 14, 2006 1:44 am 
Regular
Regular

Joined: Tue Jan 03, 2006 7:21 am
Posts: 85
I do not know but can you look into if implementing a Custom UserType will be of help in your situation. Basically it lets you write 2 methods

Code:
public Object NullSafeGet(IDataReader rs, String[] names, Engine.ISessionImplementor session, Object owner)
      {}


and

Code:
public void NullSafeSet(IDbCommand st, Object value, int index, Engine.ISessionImplementor session)
      {}


NullSafeGet is called to populate your Object when NHibernate is loading an Object while NullSafeSet is called to before NHibernate persists your Object. There are other methods that needs to be implemented as well.

Please see if this can solve your case.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Feb 23, 2006 11:15 am 
Regular
Regular

Joined: Tue Mar 15, 2005 12:38 pm
Posts: 73
Location: Bucharest
You could use IInterceptor over the session. Is not at entity level but at session level. There you could maybe do this but AFAIK inside the interceptor you cannot use the session for perfoming queries...

The ideea that there should be an interface such as ILifecycle that would be called _ALLWAYS_ seems very nice to me I am also wondering why it is not there yet (and yes I know it's not in Hibernate either:) )


Top
 Profile  
 
 Post subject: Can someone elaborate on this please?
PostPosted: Thu Jul 06, 2006 11:16 pm 
Newbie

Joined: Tue Jun 06, 2006 10:45 pm
Posts: 5
So I've run up against this issue too. I need an event that gets called when theres an Update, and I could have sworn I had it working at one point, but now it seems when I step through my code, that there is not a call to OnUpdate.

I read in the docs that a call to this is only triggered when ISession.Update is called. I'm not sure what to do because I'm using SaveOrUpdate since I'd prefer my business object not have to know whether the instance is new or existing. Is there a simple way to do an "if exists session.Update else session.Save"?

What is the rationale for NOT calling OnUpdate on every operation that triggers an UPDATE statement to the database? Will there ever be such an event? What are my options here?

Thanks for any help.

Ian


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