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.
- In the HEADER block:
"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".
Header
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