Best Practices - Handling Collections
The purpose of this document is to provide best practices to handle collections.
Collections of child instances are managed as arrays, with additional technical properties and methods that simplify their management. For persistent classes, the supervisor handles all the code, and no additional line needs to be written.
The following example of code summarizes the different concepts mentioned above. Every section of this program can be considered autonomously.
To handle this, the code is created at the document class level.
#
# The history update is done after all the other controls, and before launching the update or the creation actions.
# The percentage of update number is computed after read (if creation, no history exists)
$METHODS
Case CURPTH
When "HISTORY" : # Events on a collection
Case ACTION
When "ADDLINE_AFTER"
Gosub INIT_HISTORY_LINE
Endcase
When "" : # Global events
Case ACTION
When "UPDATE_HISTORY"
Gosub UPDATE_HISTORY
When "READ_AFTER"
Gosub COMPUTE_HISTORY
Endcase
Endcase
Return
$INIT_HISTORY_LINE
this.DOCUMENT_UPD = this.APARENT.MYDOC
this.USER_UPD=this.ACTX.USER
this.CRETIM_UPD=timestamp$
this.NBTIMES_UPD=1
Return
# A propagation rule is triggered on the history if document number is changed
$PROPERTIES
Case CURPRO
When "NUMDOC"
Case ACTION
When "PROPAGATE"
Gosub PROPAGATE_NUMDOC
Endcase
Endcase
Return
# Dedicated method usually called before the creation and the update
# Updates the history lines
# "this" is the current document instance
$UPDATE_HISTORY
Local Integer NUML, TWO_YEARS, OLDLINE, NEWLINE, NBLINES, OK, FIVE_YEARS
Local Decimal TIMESTP
# Inititialize values: current timestamp value in milliseconds, number of days for the last 5 years...
TIMESTP=val(timestamp$)
FIVE_YEARS=(date$-gdat$(day(date$),month(date$),year(date$)-5))
OK=[V]CST_AOK
OLDLINE=0
# Delete the line that is too old (if it is still present and not associated with the user)
# Compute also in this loop OLDNUM: If not null, the user is already present
OK=0
For NUML=1 To maxtab(this.HISTORY)
If this.HISTORY(NUML)<>null : # The pointer can be null if a first validation has been done
If find(this.HISTORY(NUML).ASTALIN,[V]CST_ADEL,[V]CST_ANEWDEL)=0
If this.HISTORY(NUML).USER_UPD=this.ACTX.USER
OLDLINE=NUML
Elsif val(this.CRETIME_UPD)+FIVE_YEARS*24*3600*1000<TIMESTP : # Timestamps are in milliseconds
OK=fmet this.ADELLINE("HISTORY",NUML)
Break (OK<>[V]CST_AOK)
Endif
Endif
Endif
Next NUML
# Handle the error
If OK<>[V]CST_AOK
ASTATUS=fmet this.ASETERROR("","Cannot delete line from history"-num$(NUML),[V]CST_AERROR)
Return
Endif
# Insert a line at the first position of the grid to store the most recent user updating the document
NEWLINE=fmet this.ADDLINE("HISTORY",[V]CST_AFIRSTPOS)
If NEWLINE=[V]CST_ANOTDEFINED
ASTATUS=fmet this.ASETERROR("","Cannot add line in history",[V]CST_AERROR)
Return
Endif
# If a line already existed for the customer, update the last line and delete the previous one
If OLDLINE<>0
this.HISTORY(NEWLINE).NBTIMES_UPD=this.HISTORY(OLDLINE).NBTIMES_UPD+1
OK=fmet this.ADELLINE("HISTORY",OLDLINE)
Endif
# Handle the error
If OK<>[V]CST_AOK
ASTATUS=fmet this.ASETERROR("","Cannot delete line from history"-num$(NUML),[V]CST_AERROR)
Return
Endif
# Count the number of lines in the collection
NBLINES=0
For NUML=1 To maxtab(this.HISTORY)
If this.HISTORY(NUML)<>null & find(this.HISTORY(NUML).ASTALIN,[V]CST_ADEL,[V]CST_ANEWDEL)=0
NBLINES+=1
Endif
Next NUML
# Delete the line having an index over 10
# Here the technical property AORDER is used
# But the AGETINDBYLINE method could also have been used
If NBLINES>10
OK=[V]CST_AOK
For NUML=1 To maxtab(this.HISTORY)
If this.HISTORY(NUML)<>null & find(this.HISTORY(NUML).ASTALIN,[V]CST_ADEL,[V]CST_ANEWDEL)=0
If this.HISTORY(NUML).AORDER>10
OK=fmet this.ADELLINE("HISTORY",NUML)
Break (OK<>[V]CST_AOK)
Endif
Endif
Next NUML
Endif
# Handle the error
If OK<>[V]CST_AOK
ASTATUS=fmet this.ASETERROR("","Cannot delete line from history"-num$(NUML),[V]CST_AERROR)
Return
Endif
Return
$PROPAGATE_NUMDOC
For NUML=1 To maxtab(this.HISTORY)
If this.HISTORY(NUML)<>null & find(this.HISTORY(NUML).ASTALIN,[V]CST_ADEL,[V]CST_ANEWDEL)=0
this.HISTORY(NUML).DOCUMENT_UPD = this.MYDOC
Endif
Next NUML
Return
# Computes the percentage of updates
$COMPUTE_HISTORY
Local Integer NBLINE, TOTLINE
# Count the number of lines in the collection and the total
NBLINES=0
For NUML=1 To maxtab(this.HISTORY)
If this.HISTORY(NUML)<>null & find(this.HISTORY(NUML).ASTALIN,[V]CST_ADEL,[V]CST_ANEWDEL)=0
NBLINES+=1
TOTLINE+=this.HISTORY(NUML).NBTIMES_UPD
Endif
Next NUML
# Assign the percentages
For NUML=1 To maxtab(this.HISTORY)
If this.HISTORY(NUML)<>null & find(this.HISTORY(NUML).ASTALIN,[V]CST_ADEL,[V]CST_ANEWDEL)=0
this.HISTORY(NUML).PERC_UPD=ar2(100*this.HISTORY(NUML).NBTIMES_UPD/TOTLINE)
Endif
Next NUML
Return
Refer to the Classes Standard Methods Developer Guide for more information on collections.