How to use the same temporary records in several codeunits

SagaSaga Member Posts: 15
Hello experts,

our customer want to use a complex configuration tool (third party).
It works - but is really slow. One example: When a configuration starts, the programm first creates ~100 configuration lines and copies about 10,000 entries to a "lookup" table. The user can later select from this entries to make the new configuration.
If the configuration is finished the values in the lookup table are not longer needed and can be deleted.

I want to change the program to get it faster and first thing is to get the lookup records temporary. The problem is, that there are 11 codeunits, 2 forms and 1 table concerned and in there you find local or global variables from the lookuptable (with filters or modify / insert etc.). And the program jumps through the codeunits like a rabbit hunted by hungry dogs ... :wink:

Is it possible to get a "Navision wide" global temporary record variable?

Any suggestions?

Thanks in advance
Saga

Comments

  • Marije_BrummelMarije_Brummel Member, Moderators Design Patterns Posts: 4,262
    You can add a temporarry table to a singleinstance codeunit and populate it. This stays active while the application is running.
  • SagaSaga Member Posts: 15
    You can add a temporarry table to a singleinstance codeunit and populate it. This stays active while the application is running.

    Yes, I thought about this, but...

    mustn't I do a copy loop any time I use the temp records? And this takes time too (and memory space).

    Something like:
    in codeunit
    sicuTemp.GetRecords( recTemp1 ); // recTemp1 is local temporary
    

    in single instance codeunit
    GetRecords(pio_recTemp1 : TEMPORARY Record "Lookup Values")
    
    IF recSource.FIND('-') THEN
    REPEAT
      pio_recTemp1.COPY( recSource );
      pio_recTemp1.INSERT;
    UNTIL recSource.NEXT = 0;
    

    And mustn't I copy modified records back to the single instance codeunit?

    Please correct me.


    cu
    Saga
  • Marije_BrummelMarije_Brummel Member, Moderators Design Patterns Posts: 4,262
    Once you populate a global variable in a singleinstance codeunit it stays populated.

    You need to keep track of insert modify and delete's off course and if you need to extract the table to a form, you need to copy all records one by one.

    Maybe you can try using the findrecord and nextrecord directly on the temprecord in the singleinstancecodeunit. Don';t know if this works though, never tried it.
  • ara3nara3n Member Posts: 9,257
    If you don't want to loop through to copy the records, in single instance codeunite write your own function. For example

    MySingleInstanceCU.insetRecord;

    if MySingleInstanceCU.getFirst then repeat

    MySingleInstanceCU.GetCurrRecord(MyRecord);
    MySingleInstanceCU.DeleteRecord;

    until MySingleInstanceCU.NextRect = 0;


    You have to implement all these functions in the single instance codeunit.
    Ahmed Rashed Amini
    Independent Consultant/Developer


    blog: https://dynamicsuser.net/nav/b/ara3n
  • SagaSaga Member Posts: 15
    But how can I access these temporary records (now stored in the single instance codeunit) from the other codeunits? Must I always copy them (like the code examle above) to another temporary record variable of the other codeunit where I want to set a filter or something similar?

    Or is it easier and I'm just not seeing the wood for the trees?
  • SagaSaga Member Posts: 15
    ara3n wrote:
    You have to implement all these functions in the single instance codeunit.

    That's what I feared ;-)

    I'm currently on the long way developing...
  • SagaSaga Member Posts: 15
    Just a related question:

    To realize the find functions I sometimes must set the current key and filtes. That should work even if I access the records from two different codeunits with different keys and filters at the "same" time (within one function call).

    What do you think? Is this possible??
  • Marije_BrummelMarije_Brummel Member, Moderators Design Patterns Posts: 4,262
    Saga wrote:
    Just a related question:

    To realize the find functions I sometimes must set the current key and filtes. That should work even if I access the records from two different codeunits with different keys and filters at the "same" time (within one function call).

    What do you think? Is this possible??

    Are you still refering to temporary tables? If yes, and the records are defined in different codeunits, the data in the tables might not be the same.

    If no, you can filter in the same table from different codeunits at the same time. The tablelock is only implemented when you change the data.
  • krikikriki Member, Moderator Posts: 9,118
    Saga wrote:
    ara3n wrote:
    You have to implement all these functions in the single instance codeunit.

    That's what I feared ;-)

    I'm currently on the long way developing...
    Not really, you can do this quite easily.

    Saga wrote:
    Just a related question:

    To realize the find functions I sometimes must set the current key and filtes. That should work even if I access the records from two different codeunits with different keys and filters at the "same" time (within one function call).

    What do you think? Is this possible??
    Yes it is.
    I give some examples on how to start developping:
    The Codeunit (lets name it "TT"):
    Function TTFIND(VAR PtmpTempRecord ; ItxtFindString : Text): OblnFindResult:BOOLEAN
    BEGIN
      tmpTemprecord.COPY(PtmpTempRecord);
      OblnFindResult := tmpTemprecord.FIND(ItxtFindString);
      PtmpTemprecord.COPY(tmpTempRecord);
    END;
    
    Function TTNEXT(VAR PtmpTempRecord ; IintSteps): OintResult:INTEGER
    BEGIN
      tmpTemprecord.COPY(PtmpTempRecord);
      OintResult := tmpTemprecord.NEXT(IintSteps);
      PtmpTemprecord.COPY(tmpTempRecord);
    END;
    
    Function TTINSERT(ItmpTempRecord ; IblnInterceptError:BOOLEAN): OblnResult:BOOLEAN
    BEGIN
      tmpTemprecord := PtmpTempRecord
      IF IblnInterceptError THEN
        OblnResult := tmpTemprecord.INSERT(FALSE)
      ELSE BEGIN
        tmpTemprecord.INSERT(FALSE);
        EXIT(TRUE);
      END;
    END;
    

    And now how to use it:
    IF-FIND-REPEAT-NEXT
    tmpTempRecord.RESET;
    tmpTempRecord.SETCURRENTKE(...);
    tmpTempRecord.SETRANGE(...);
    IF cduTT.TTFIND(tmpTempRecord,'-') THEN
      REPEAT
        // do something
      UNTIL cduTT.TTNEXT(tmpTempRecord,1) = 0;
    

    insert a record and intercept INSERT-error
    CLEAR(tmpTempRecord);
    tmpTempRecord."Field 1" := "Value 1";
    tmpTempRecord."Field 2" := "Value 2";
    tmpTempRecord."Field 3" := "Value 3";
    IF NOT cduTT.TTINSERT(tmpTempRecord,TRUE) THEN
      ERROR('Insert Not Succeeded');
    

    insert a record and let INSERT-error generate an error
    CLEAR(tmpTempRecord);
    tmpTempRecord."Field 1" := "Value 1";
    tmpTempRecord."Field 2" := "Value 2";
    tmpTempRecord."Field 3" := "Value 3";
    cduTT.TTINSERT(tmpTempRecord,FALSE);
    

    And this you can use in more objects at the same time, because the 'pointer' of the record (with a FIND-REPEAT-NEXT) remains in a local variable.
    Regards,Alain Krikilion
    No PM,please use the forum. || May the <SOLVED>-attribute be in your title!


  • ara3nara3n Member Posts: 9,257
    wow Kriki =D>
    Ahmed Rashed Amini
    Independent Consultant/Developer


    blog: https://dynamicsuser.net/nav/b/ara3n
  • Marije_BrummelMarije_Brummel Member, Moderators Design Patterns Posts: 4,262
  • krikikriki Member, Moderator Posts: 9,118
    And something nice I just tested (I got curious).
    I created a temporary recordreference-variable with dimensions.
    The first dimension I created for table X and the second dimension for table Y.
    I put in both some records and it was all accepted!
    So, this means that a recordreference can contain DIFFERENT tables in DIFFERENT dimensions!!!!!!!!
    Regards,Alain Krikilion
    No PM,please use the forum. || May the <SOLVED>-attribute be in your title!


  • Marije_BrummelMarije_Brummel Member, Moderators Design Patterns Posts: 4,262
    kriki wrote:
    So, this means that a recordreference can contain DIFFERENT tables in DIFFERENT dimensions!!!!!!!!

    Yep this is true. We've used this for our document module to create nesting in exporting saleslines with salesheaders etc. still using one recref.
  • SagaSaga Member Posts: 15
    Many, many thanks to kriki and Mark.

    I've just made a little test and it worked. I will now implement this in all places.

    Regards
    Saga
  • SagaSaga Member Posts: 15
    Just one more question:

    How can I realize a MODIFYALL function in a codeunit similar to the functions above?

    Regards
    Saga
  • krikikriki Member, Moderator Posts: 9,118
    Saga wrote:
    Just one more question:

    How can I realize a MODIFYALL function in a codeunit similar to the functions above?

    Regards
    Saga
    I am afraid that you must do that 1 by 1 with a REPEAT UNTIL.
    Or write a MODIFYALL per field.
    Or maybe with the help of variant.
    Something like (didn't test it!)
    Function TTMODIFYALL(VAR PtmpTempRecord,IintFieldID : Integer;IvarNewValue);
    BEGIN
      // "IintFieldID" is the ID of the field you want to change
      // "IvarNewValue" is the new value (this is a variant)
      tmpTemprecord.COPY(PtmpTempRecord);
      CASE IintFieldID OF
         tmpTemprecord.FIELDID("Field 1"): tmpTemprecord.MODIFYALL("Field 1",IvarNewValue);
         tmpTemprecord.FIELDID("Field 2"): tmpTemprecord.MODIFYALL("Field 2",IvarNewValue);
        ...
      END;
      PtmpTemprecord.COPY(tmpTempRecord);
    END;
    
    Remember that Variants don't work with all variable types.
    Regards,Alain Krikilion
    No PM,please use the forum. || May the <SOLVED>-attribute be in your title!


Sign In or Register to comment.