Managing CRUD Combined Objects

Introduction Table description Main principles YCOMBD class definition
YCOMB class definition YCOMB representation YCOMB_CSTD script YCOMB_RSTD script

Introduction

A combined object is made of a unique table containing a key with two components. This table has multiple records that are associated with a given value of the first key component.

In this mode:

  • The header includes the first component of the key, as well as additional fields with the same value for all records.
  • The grid displays a row for each record with the same first key value.

While the generation of the CRUD code for this type of object is not automated, objects can be created using the supervisor.

Table description

Table "YCOMB [YCO]" has the following structure (technical columns are not listed):

Column Type Description Place
YGRP Character 10 Group Header
YNAM Character 80 Group description Header
YSGRP Character 5 Group member Line
YTEXT Character 40 Member text Line
YDATE Date Member Date Line
YNUM Decimal 9.2 Member value Line

"YCO0" is the unique key of the table. It has no duplicates and it is made of two components: YGRP+YSGRP.

Main principles

  • The CRUD methods are defined in the table. A class called "YCOMBD" was created for this purpose. Any business rule associated with updating the table is defined with no direct attached representation.
  • An interface class named "YCOMB" and its representation were created to manage the user interface. They run:
    • The query based on a list of the first key component.
    • A collection of "YCOMBD" instances, each instance being a line attached to a given header value.
  • The AREAD, AINSERT, AUPDATE, and ADELETE methods in the interface class invoke the CRUD methods of the "YCOMBD" class within a loop that runs through all the records.

"YCOMBD" class definition

This class has the following characteristics:

  • It is persistent, based on the "YCOMB" table.
  • The class index is "YCO0" (YGRP+YSGRP).
  • The Creation, Read, Update, and Deletion standard methods are available.
  • The following properties are present: YGRP, YNAM, YSGRP, YTEXT, YDATE, YNUM, CREDATTIM, UPDDATTIM, AUUID, CREUSR, and UPDUSR.
  • In the Mapping tab, all the CRUD check boxes are selected.

As there are no particular controls on this class, there is no script associated with it. However, you can add one if necessary.

"YCOMB" class definition

This class has the following characteristics:

  • It is interface-typed, with a key named "YGRP".
  • A collection named "YCOMBD" was declared with the following characteristics:
    • Minimum=0 and Maximum=0
    • Insertion, Deletion, Sorting, and Addition check boxes selected.
  • A script named "YCOMB_CSTD" was added.
  • The Creation, Read, Update, and Deletion standard methods are available.
  • The following fields are present on the Properties tab:
    • "YGRP" and "YNAM" are available in the header.
    • "YCOMBD", which is an instance of the "YCOMBD" collection, is part of this collection.

"YCOMB" representation

This representation has the following characteristics:

  • It is associated with the "YCOMB" class, with "YCOMB" as an instance name.
  • Managed behaviors are Creation, Modification, and Deletion.
  • A script named "YCOMB_RSTD" was defined.
  • No properties or methods were added.
  • The page organization is based on two sections: HEADER and LINES. Each section contains two blocks called HEADER and LINES.
  • The properties are:
    • In the HEADER block:
      • "YCOMB.YGRP" with the alias "YGRP"
      • "YCOMB.YNAM" with the alias "YNAM"

      Both can be found on all facets and can be entered.

    • In the LINES block:
      • "YCOMB.YCOMBD.YSGRP" with the alias "YGRP"
      • "YCOMB.YCOMBD.YTEXTE" with the alias "YTEXTE"
      • "YCOMB.YCOMD.YSDATE" with the alias "YDATE"
      • "YCOMB.YCOMBD.YNUM" with the alias "YNUM".

      All can be found on facets Detail and Edit, and can be entered.



"YCOMB_CSTD" script

Header Read method Insertion method Update method
Delete method Subprograms Events on collection Events on properties

The script implements the CRUD method for the combined object. The "YCOMB" class is not persistent, therefore, the AREAD, AINSERT, AUPDATE, and ADELETE events are used. They are located in the script, right after the $METHOD label in case "CURPTH" is empty.

Additionally, events AREAD_AFTER and ADDLINE_AFTER have to be handled on every "YCOMBD" record. When this happens, "CURPTH" is equal to "YCOMBD".

The beginning of the script is as follows:

sh
###############
# METHODS
###############
$METHODS
Case CURPTH
    When ""
        Case ACTION
            When "AREAD"                  : Gosub AREAD
            When "AINSERT"                : Gosub AINSERT
            When "AUPDATE"                : Gosub AUPDATE
            When "ADELETE"                : Gosub ADELETE
        Endcase
    When "YCOMBD"
        Case ACTION
            When "AREAD_AFTER"   : Gosub YCOMBD_AREAD_AFTER
            When "ADDLINE_AFTER" : Gosub YCOMBD_ADDLINE_AFTER
        Endcase
Endcase
Return

Read method

The AREAD method performs a reading loop on the "YCOMBD" table. For every existing record, the ADDLINE method is invoked on the "YCOMBD" collection to add a line at the end of the table. The standard AREAD method is then used on the line instance to fill the record. The loop process stops if any error is found. This corresponds to the following code:

sh
$AREAD
Local File YCOMB [YCO]
Local Integer ILINE
  For [YCO] Where YGRP=this.YGRP
    ILINE = fmet this.ADDLINE("YCOMBD",CST_ALASTPOS)
    [L]ASTATUS = fmet this.YCOMBD(ILINE).AREAD([F:YCO]YGRP,[F:YCO]YSGRP)
    # The syntax Break condition means that if condition is true (ie 1), a Break 1 is done (Break 0 does nothing)
    Break [L]ASTATUS>=[V]CST_AERROR
  Next
Return

Insertion method

Consistency checks must be performed on the insertion method:

  • At least one line must exist.
  • No duplicate value of lines is allowed.

The corresponding sub-program is CTL_CONSISTENCY.

A loop is performed to insert all of the lines with "CST_ANEW" as the line status. While in insertion mode, the only other status that can be encountered is "CST_ANEWDEL".

In this case, there is no need to make sure this.YCOMBD(ILINE) is not null because the instance collection was created by only adding lines at the end of the table, and because the deletion is exclusively logical.

The code is as follows:

sh
$AINSERT
Local Integer ILINE
# Consistency controls
  Gosub CTL_CONSISTENCY : If [L]ASTATUS>=[V]CST_AERROR : Return : Endif
# Loop on every line that has to be created
  For ILINE=1 To maxtab(this.YCOMBD)
    If this.YCOMBD(ILINE)<>null
      If this.YCOMBD(ILINE).ASTALIN = CST_ANEW
        [L]ASTATUS = fmet this.YCOMBD(ILINE).AINSERT()
        Break ([L]ASTATUS>=[V]CST_AERROR)
      Endif
    Endif
  Next
Return

Update method

The same initial control is performed on the update method.

Three loops handle the different modifications that are made on the lines:

  • The first loop deletes the lines where "ASTALIN" equals "CST_ADEL".
  • The second loop updates the lines where "ASTALIN" equals "CST_AUPD".
  • The third loop updates the lines where "ASTALIN" equals "CST_ANEW".

The code is as follows:

sh
$AUPDATE
Local Integer ILINE
  Gosub CTL_CONSISTENCY : If [L]ASTATUS>=[V]CST_AERROR : Return : Endif
# Delete the lines
  For ILINE= 1 To maxtab(this.YCOMBD)
    If this.YVOMB(ILINE)<>null
      If this.YCOMBD(ILINE).ASTALIN = [V]CST_ADEL
        [L]ASTATUS = fmet this.YCOMBD(ILINE).ADELETE()
        If [L]ASTATUS>=[V]CST_AERROR : Return : Endif
      Endif
    Endif
  Next
# Update the lines
  For ILINE= 1 To maxtab(this.YCOMBD)
    If this.YCOMBD(ILINE)<>null
      If this.YCOMBD(ILINE).ASTALIN = [V]CST_AUPD
        [L]ASTATUS = fmet this.YCOMB(ILINE).AUPDATE()
        If [L]ASTATUS>=[V]CST_AERROR : Return : Endif
      Endif
    Endif
  Next
# Insert the lines
  For ILINE= 1 To maxtab(this.YCOMBD)
    If this.YCOMBD(ILINE)<>null
      If this.YCOMBD(ILINE).ASTALIN = [V]CST_ANEW
        [L]ASTATUS = fmet this.YCOMBD(ILINE).AINSERT()
        Break [L]ASTATUS>=[V]CST_AERROR
      Endif
    Endif
  Next
Return

Delete method

A loop is initiated on every line that invokes the DELETE method. The loop stops when an error occurs.

The code is as follows:

sh
$ADELETE
Local Integer ILINE
  For ILINE= 1 To maxtab(this.YCOMBD)
    If this.YCOMBD(ILINE)<>null
      [L]ASTATUS = fmet this.YCOMBD(ILINE).ADELETE()
      Break [L]ASTATUS>=[V]CST_AERROR
    Endif
  Next
Return

"CTL_CONSISTENCY" subprogram

This subprogram performs a loop on the "YCOMBD" collection. If at least one line is found, "LINE_FOUND" is set to 1. A second loop, concatenated with the first one, checks whether the same "YGRP" value has been used on another line. If this is the case, an error is invoked and the loop is stopped.

The code is as follows:

sh
# Check the consistency
$CTL_CONSISTENCY
Local Shortint LINE_FOUND
Local Integer IL, JL
  For IL=1 To maxtab(this.YCOMBD)
    If this.YCOMB(IL)<>null
      If find(this.YCOMB(IL).ASTALIN,[V]CST_ADEL,[V]CST_ANEWDEL)=0
        LINE_FOUND=1
        For JL= IL+1 To maxtab(this.YCOMBD)
          If this.YCOMB(JL)<>null
            If find(this.YCOMB(JL).ASTALIN,[V]CST_ADEL,[V]CST_ANEWDEL)=0
              If this.YCOMB(IL).YSGRP= this.YCOMB(JL).YSGRP
                [L]ASTATUS = fmet this.ASETERROR("YGRP", this.YCOMB(IL).YSGRP -":"-mess(94,139,1),[V]CST_AERROR)
                Break 2
              Endif
            Endif
          Endif
        Next JL
      Endif
    Endif
  Next IL
  If LINE_FOUND=0
    [L]ASTATUS = fmet this.ASETERROR("",mess(178,123,1),[V]CST_AERROR)
  Endif
Return

Events on the "YCOMB" collection

Two events are necessary to properly manage the collection:

  • The reading loop adds lines to the grid and assigns the "CST_ANEW" status to each of them. They should be considered as existing lines. For this reason, "ASTALIN" has to be assigned to "[v]CST_ALL".
  • Every time a line is added to the grid, it is necessary to apply the header properties on the new line (YGRP and YNAM).

This provides the following code:

sh
$YCOMB_AREAD_AFTER
# Assign ASTALIN to CST_ALL (they have the value 'CST_ANEW' just after AREAD method)
this.ASTALIN = [V]CST_ALL
Return
$YCOMB_ADDLINE_AFTER
# To initialize properties of the header
this.YGRP = this.APARENT.YGRP
this.YNAM = this.APARENT.YNAM
Return

Events called on the properties

The following additional controls must be performed on the properties (after the $PROPERTIES label in the script below):

  • If the "YGRP" or "YNAM" properties are modified in the header, the modification should also apply to the lines.
  • When a member is added to the group, no duplicate values are allowed in the grid. This control is performed at another level.

This provides the following code:

sh
$PROPERTIES
  # If YGRP or YNAM have been modified, perform a loop to update all the lines
  Case CURPRO
    When "YGRP"
      Case ACTION
        When 'PROPAGATE'
          Local Integer IL
          For IL= 1 To maxtab(this.YCOMBD)
            If this.YCOMBD(IL)<>null
              this.YCOMBD(IL).YGRP = this.YGRP
            Endif
          Next IL
      Endcase
    When "YNAM"
      Case ACTION
        When 'PROPAGATE'
          Local Integer IL
          For IL= 1 To maxtab(this.YCOMBD)
            If this.YCOMBD(IL)<>null
              this.YCOMBD(IL).YGRP = this.YGRP
            Endif
          Next IL
      Endcase
  Endcase
Return

Script associated with the "YCOMB" representation

This script manages the list of codes by using a table in memory. The code is as follows:

sh
#########################
# Representation YCOMB
#########################
###############
# METHODS
###############
$METHODS
Case CURPTH
   When ""
     Case ACTION
       When "AQUERY_DECODE_CRITERIA_AFTER" : Gosub AQUERY_DECODE_CRITERIA_AFTER
       When "AQUERY_PRIMARYKEYS_AFTER"     : Gosub AQUERY_PRIMARYKEYS_AFTER
       When "AQUERY_OPEN_AFTER"            : Gosub AQUERY_OPEN_AFTER
       When "AQUERY_TRANS_AFTER"           : Gosub AQUERY_TRANS_AFTER
       When "AQUERY_CLOSE_AFTER"           : Gosub AQUERY_CLOSE_AFTER
     Endcase
Endcase
Return
#################### Standard Query Events #########################
$AQUERY_DECODE_CRITERIA_AFTER
Raz NBPRO
NBPRO += 1
TBPRO(NBPRO) = "YGRP" : TBTYP(NBPRO) = 7 : TBPTH(NBPRO) = "YCOMBH.YGRP" : TBFIL(NBPRO) = "[LNK_]YGRP"
NBPRO += 1
TBPRO(NBPRO) = "YNAM" : TBTYP(NBPRO) = 7 : TBPTH(NBPRO) = "YCOMBH.YNAM" : TBFIL(NBPRO) = "[LNK_]YNAM"
Return
$AQUERY_PRIMARYKEYS_AFTER
ASTDKEY = "[LNK_]YGRP"
Return
$AQUERY_OPEN_AFTER
Local File YCOMB [QRY_YC]
Local Integer I : I=0
Local Char TYGRP(12)(1..), TYNAM(40)(1..)
For [QRY_YC]YCO0(1)
 I+=1
 TYGRP(I) = [F:QRY_YC]YGRP
 TYNAM(I) = [F:QRY_YC]YNAM
Next
# A test must be done on I (this will be fixed later)
# On empty arrays, for behaves as if 32,768 lines were here!
If I<>0
  Local File (Char YGRP(100),Char YNAM(100)) From Variable TYGRP,TYNAM As [LNK_]
Else
  Local File YCOMB [LNK_]
Endif
Return
$AQUERY_TRANS_AFTER
this.YCOMB.YGRP = [LNK_]YGRP
this.YCOMB.YNAM = [LNK_]YNAM
Return
$AQUERY_CLOSE_AFTER
Close Local File [LNK_]
Return