Persistence of data when Prodatasets are passed BY-REFERENCE

Posted by ge1971 on 12-Mar-2010 11:10

I'm returning to OE development after a couple of years away and am struggling with (what I think) is a fairly straightforward problem; probably best illustrated by some (simplified) code from my prototyping work so far:

test.p

CREATE ttEnv.

ttEnv.hServer = (either this session or appserver handle).

RUN ClientWindow.w (INPUT DATASET dsEnv BY-REFERENCE).

ClientWindow.w (INPUT PARAMETER DATASET FOR dsEnv).

MAIN-BLOCK:
  clsCustomer = NEW Customer(INPUT DATASET dsEnv BY-REFERENCE).
  RUN enable_UI.
  IF NOT THIS-PROCEDURE:PERSISTENT THEN
    WAIT-FOR CLOSE OF THIS-PROCEDURE.         
  DELETE OBJECT clsCustomer. 
END.


ON CHOOSE OF btnSearch:

  clsCustomer:getRecords(OUTPUT DATASET dsCustomer).

END.

Customer class

(constructor) METHOD Customer (INPUT DATASET dsEnv)

     clsDataHandler = NEW DataHandler(INPUT DATASET dsEnv BY-REFERENCE).

END METHOD.


METHOD getRecords (OUTPUT DATASET dsCustomer):

     clsDataHandler.getRecords (INPUT customertable,

                                OUTPUT DATASET dsCustomer)
END METHOD.

DataHandler class

(constructor) METHOD DataHandler (INPUT DATASET dsEnv)

END METHOD.


METHOD getRecords (INPUT tablename, OUTPUT DATASET dsCustomer):

   RUN myGetRecordsProc.p ON ttEnv.hServ  <etc...>
END METHOD.

By way of explanation...

test.p sets up my environment (in this case whether the get record procedure can be run in this session, or over an appserver connection).

The test window creates an instance of my Customer class and passes dsEnv to it's constructor; the Customer class does a similar thing, passing dsEnv to the constructor of the DataHandler class.

What I'm trying to achieve is to share the dsEnv dataset across all these classes, without having to pass it as a parameter every time I use a method.

Everything was working perfectly well until I decided to look into optimising the code by passing the dsEnv dataset BY-REFERENCE.

Logically this makes sense to me - you only want a single instance of the dsEnv dataset in each client session, so copying it around needlessly seems wasteful.

Again, everything continued to work fine until I added the BY-REFERENCE code I've highlighted in the Customer class constructor.

I've checked, and the dsEnv data is still available in the DataHandler constructor, but I get a "record not available" when the DataHandler.getRecords method is invoked.

...and I've confirmed that if I remove the highlighted BY-REFERENCE code it works perfectly well.

I'm pretty sure the answer is down to something fairly straightforward, but I've been away from OE development for a little while and have drawn a blank so far, so if anyone has the time to review that and remind me what I'm over-looking then I'd very much appreciate it.

Gareth.

All Replies

Posted by Thomas Mercer-Hursh on 12-Mar-2010 11:28

Without addressing the actual question you are asking, let me suggest that you take a step backward and think about your architecture.  In particular, I would do some reading about OERA and think about achieving that kind of layer separation in your application and look around at various patterns for handling data in such layers.  A quick summary of some methods is here
http://www.cintegrity.com/content/Patterns-Managing-Relational-Data-OOABL .  You should also be thinking about core OO concepts such as encapsulation and separation of concerns.  There are a couple of whitepapers here http://www.cintegrity.com/content/Basic-Concepts which might give you a foundation.  As a general rule, one doesn't want to have a PDS being passed around all over the place.  There is one pattern mentioned in the PUG talk in which a PDS is used as a parameter between the data layer and the business layer ... I don't like that either, but it should be the max.  Much better, if you are going to focus on PDS, is to look for inspiration in something like the Model-Set-Entity pattern which you will see discussed on other threads in this forum.  It manages to present a very clear OO looking object in the business entity, despite having the data reside i a PDS.

Posted by ge1971 on 12-Mar-2010 13:24

Thank you for the reply Thomas, those links look like exactly the sort of thing I've been looking for to provide more information on this sort of implementation - not read them in detail yet, but it's Friday night and some things can wait until Monday !

I worked on a project implementing the OERA design back in 2007, as well as having some background in other OO development; so I'm fairly comfortable with OO principles (encapsulation, inheritance, etc); but I've recently returned to re-examine the OERA concepts and Progress class-based techniques as I'm trying to prototype some examples for my current company whose software runs in a client-server (Appserver) environment (currently v8-9 ADM interfaces and procedural code), and this environment is a quite different to the OERA project I originally worked on back then, so it's almost like starting over !

P.S.

Regarding the original question, I realised after posting that in simplifying the code examples I removed FIND FIRST ttEnv just before the RUN ...on server-handle call in the DataHandler class. I guess after reading the white papers I may well approach this differently, but if anyone's inclined to review the example and tell me what's going on I think the information would still be very useful.

Thanks again,

Gareth

Posted by guilmori on 12-Mar-2010 13:49

Gareth,

Try to put a

     message dataset dsEnv:handle view-as alert-box.

in your DataHandler constructor and in DataHandler.getRecords method.
You should notice it is not the same handle displayed.

This is because BY-REFERENCE makes the caller dataset valid in the callee only for the duration of the call.
In your case, this means that as soon as the NEW DataHandler() finishes, the reference is gone. No very usefull huh ?

You could try to play with BIND and REFERENCE-ONLY, but a much simpler approach is to encapsulate you dsEnv into a class, and pass the class instance in parameter.

Posted by ge1971 on 15-Mar-2010 04:31

Thank you Guillaume, that's exactly what's going on .

As you said, the dataset is valid only for the duration of the constructor and so won't be available elswhere if it's implemented BY-REFERENCE (as in the code posted). An important point I originally overlooked !

The comments from yourself and Thomas have helped clear this up, so I now understand more clearly what's going on; and also point me to other areas to look into for a better implementation of this concept, so thanks again to both of you for your assistance.

Gareth

This thread is closed