-->
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.  [ 9 posts ] 
Author Message
 Post subject: Correct use of an interceptor - only on changed objects
PostPosted: Thu May 18, 2006 10:46 am 
Beginner
Beginner

Joined: Tue Mar 28, 2006 3:44 am
Posts: 22
Hi all,

I want to use an Interceptor to implicitly save the current timestamp and the current user who is logged on and changed the object. So far there is no problem to get the information. I played around with some settings, first of all without an Interceptor. I wanted to know if NHibernate detects which objects have been changed and which not, if I use SaveOrUpdate() for a whole list. Until now I haven't had any success in proving my assumption.

I read through a couple of documentation but I guess I don't get it all by now. So here's what I want (accutally have) ;) to do.
It's a multi-tier web application and it handles everything relatively normal.
    1. Recieve a request and retrieve objects
    2. Render output, close NHibernate session and store retrieved objects e.g. in HTTP-Session
    3. On the next request update stored objects, do some business processing and save or update everything in the database

During this process there is no garanty that all temporarly stored objects were changed. But if every object will be send back to the database the interceptor will overwrite every date and username although the particular object might not have been changed.

What can I do to avoid this problem? As I said I played around with the information abount optimistic locking and versioning stuff but the SQL output didn't indicate any version checking activity. So maybe I'm completely on the wrong track.

Thanks in advance for any hints and suggestions,
Chavez


Top
 Profile  
 
 Post subject:
PostPosted: Mon May 22, 2006 2:37 pm 
Expert
Expert

Joined: Fri Oct 28, 2005 5:38 pm
Posts: 390
Location: Cedarburg, WI
We have our entities track their own dirty status. I.e. each property setter sets the object's dirty flag (we use field rather than property access, so NHibernate never triggers setting the dirty flag). Then in IInterceptor.PreFlush, we check this dirty flag, and if set, call our method that sets the current user and date. Finally, IInterceptor.PostFlush clears the dirty flag.


Top
 Profile  
 
 Post subject:
PostPosted: Tue May 23, 2006 2:56 am 
Beginner
Beginner

Joined: Tue Mar 28, 2006 3:44 am
Posts: 22
Thanks for your hint.
I was thinking about such a solution over the weekend too. So far I implemented a silghtly different prototype. We have a kind of facade to truly seperate the data access from the business logic and by now this facade clears the dirty flag. But I guess your suggestion is a bit more convenient and maybe a bit faster too. :)

Thanks again for your help!
Chavez


Top
 Profile  
 
 Post subject:
PostPosted: Tue May 23, 2006 10:14 am 
Expert
Expert

Joined: Fri Oct 28, 2005 5:38 pm
Posts: 390
Location: Cedarburg, WI
The weird part of our solution though is that the dirty flag on our entities is a property with a public getter and private setter. We don't want just anybody to clear the dirty flag. The interceptor "cheats" by using reflection to clear the property. There must be a safer way to do this though, e.g. make the setter public but throw an exception if not called from the interceptor, but I don't know how to do that kind of authentication ...

Oh yeah, one other thing -- in the regular property setters, only set the dirty flag if the new value is actually different from the old value ...


Top
 Profile  
 
 Post subject:
PostPosted: Tue May 23, 2006 10:26 am 
Expert
Expert

Joined: Thu Jan 19, 2006 4:29 pm
Posts: 348
Nels_P_Olsen wrote:
There must be a safer way to do this though, e.g. make the setter public but throw an exception if not called from the interceptor, but I don't know how to do that kind of authentication ...


Code:
      System.Diagnostics.StackTrace stack = new System.Diagnostics.StackTrace(false);
      bool wasInterceptor = false;
      for (int i = stack.FrameCount - 1; i >= 0; i++)
      {
        System.Diagnostics.StackFrame frame = stack.GetFrame(i);
        if (frame.GetMethod().DeclaringType == typeof(YourInterceptor))
        {
          wasInterceptor = true;
          break;
        }
      }
      if (!wasInterceptor)
        throw new InvalidOperationException("Not called from interceptor");


The code is not tested... But should work. Adjust the code according to Your taste.

Gert

_________________
If a reply helps You, rate it!


Top
 Profile  
 
 Post subject:
PostPosted: Wed May 24, 2006 3:00 am 
Senior
Senior

Joined: Thu Aug 25, 2005 3:35 am
Posts: 160
i was just going to post the same solution, but do understand that this is very slow code. The reflection cheat is faster. Better still would be a dynamic method, since you are using 2.0, that is fairly easy.


Top
 Profile  
 
 Post subject:
PostPosted: Wed May 24, 2006 3:17 am 
Beginner
Beginner

Joined: Tue Mar 28, 2006 3:44 am
Posts: 22
Of course this problem should be solved. In my case that's not a really big deal, the logic has the explicit right to reset the flag. This is a tribute to undo operations without checking the database again. It is quite obvious that this is not really safe, but I have to live with it. At least now. :)

A little thing concerns me about the provided solution. If the DTO has to check whether the type of the "calling" object was an Interceptor or not, the DTO has to "know" the Interceptor. I don't know if this is a good move. We don't give the DTO any knowledge about "outside" classes. It's just a dumb transport container with some value checking for his own properties. In my opinion this is a good way of decoupling the DTOs. What are you guys thinking about this?

Greetings,
Chavez


Top
 Profile  
 
 Post subject:
PostPosted: Wed May 24, 2006 7:17 am 
Expert
Expert

Joined: Thu Jan 19, 2006 4:29 pm
Posts: 348
TheShark wrote:
i was just going to post the same solution, but do understand that this is very slow code. The reflection cheat is faster.

Well, depnding on Your situation You probably do not need to wlak trough full stack trace. I might want to check only the first stack frame above the current code... But I admit I have no idea about the speed of code...

Chavez2K2 wrote:
It's just a dumb transport container with some value checking for his own properties. In my opinion this is a good way of decoupling the DTOs. What are you guys thinking about this?


You mean like Anemic Domain Model (http://www.martinfowler.com/bliki/AnemicDomainModel.html)?

Gert

_________________
If a reply helps You, rate it!


Top
 Profile  
 
 Post subject:
PostPosted: Wed May 24, 2006 7:30 am 
Senior
Senior

Joined: Thu Aug 25, 2005 3:35 am
Posts: 160
gert wrote:
Well, depnding on Your situation You probably do not need to wlak trough full stack trace. I might want to check only the first stack frame above the current code... But I admit I have no idea about the speed of code...


The walking isn't that slow, it's the getting to the stalk trace. From what I gather, that something you only want to do in exception tracing. But maybe it has changed in 2.0.
It all depends on your usage. But if nh is touching that code each time it sets a property, then I would seriously consider profiling it.


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