This section looks at attributes and methods that give you access to, and information about, the ProDataSet's Data-Relations. First, there is a NUM-RELATIONS attribute to return the number of Data-Relations, as shown in the following syntax:
Syntax
[ integer-var = ] dataset-handle:NUM-RELATIONS
You can retrieve the handle to a particular relation using the GET-RELATION method with its numeric index in the ProDataSet or its name. This is the syntax for the GET-RELATION method:
relation-index-expr is an integer expression that evaluates to the one-based index of the Data-Relation in the ProDataSet.
relation-name-expr is a character expression that evaluates to the name of the Data-Relation.
Once you have a relation object, you can access its attributes. CHILD-BUFFER returns the buffer handle of the child member of the Data-Relation, as shown in the following syntax:
Syntax
[ buffer-handle = ] relation-handle:CHILD-BUFFER
Likewise, PARENT-BUFFER returns the parent buffer handle of the relation, as shown in the following syntax:
Syntax
[ buffer-handle = ] relation-handle:PARENT-BUFFER
Two attributes and method provide access to a relation through one of the member buffer handles. The NUM-CHILD-RELATIONS attribute returns the number of Data-Relations for which the buffer is the parent. There might be more than one because a buffer can be a parent in multiple relations, with different children. This is the syntax for the NUM-CHILD-RELATIONS attribute:
As with the ProDataSet's GET-BUFFER-HANDLE method, you can use the GET-CHILD-RELATION method to walk through the list of child relations for a particular parent buffer using the buffer index within the list. This is the syntax for the GET-CHILD-RELATION method:
You can also point back from the child buffer of a Data-Relation to its PARENT-RELATION, as shown in the following syntax:
[ handle-var = ] buffer-handle:PARENT-RELATION
Because a buffer cannot have more than one parent, there is no need for an attribute to return the number of parent buffers.
This code sample and output for DynamicMain2.p confirms the parent and child of the ProDataSet's one relation:
/* This block shows some of the Data-Relation methods and attributes. */
hRelation = hDataSet:GET-RELATION(1).
MESSAGE "Buffer" hRelation:CHILD-BUFFER:NAME "is the child of"
hRelation:PARENT-BUFFER:NAME
VIEW-AS ALERT-BOX.
The AVM creates a dynamic query representing each Data-Relation in the ProDataSet. This query provides filtering of child records in each relation so that you can use it if you want to walk the child records for the current parent. If you attach this query to a browse object, the browse is automatically refreshed with the right child records as the currently selected parent record changes. Several attributes provide access to and information about this query.
The first attribute is the relation's WHERE-STRING, which returns the current WHERE clause used to link the child of the relation to its parent, beginning with the keyword WHERE but not including the FOR EACH phrase of a QUERY-PREPARE method on a query. This attribute evaluates to the query string that the AVM generates for you based on the relation between the parent and the child. You could use this attribute to build an extended query of your own based on the default relationship but extending it in some way, as shown with this syntax:
Syntax
[ character-var = ] relation-handle:WHERE-STRING
The RELATION-FIELDS attribute returns the list of join fields between the parent and child as specified in the relation definition. This can be useful in code that exploits or extends the list of join fields without parsing the WHERE-STRING. In the default case, it provides essentially the same information but not necessarily in an ideal form for analyzing the relation. This is the syntax for the RELATION-FIELDS attribute:
You can access the dynamic query itself through the relation's QUERY attribute, as shown using the following syntax:
Syntax
[ handle-var = ] relation-handle:QUERY
This returns the handle of the navigation query that the AVM manages to filter children of the current parent when navigating the ProDataSet. This is not the same as the query defined for a Data-Source. This automatically generated query expresses the relation between parent and child temp-tables. This handle cannot be set, and the query cannot be modified. You can use this query to navigate the child records. This might be useful because it is automatically opened for you each time the parent changes. The AVM can insert the correct parent key field values directly into the child query each time the parent record changes, so it does not need to be fully prepared when the parent changes. This makes this default query more efficient than an ABL query you would re-prepare and reopen yourself each time the parent changes. You can also prepare and open your own query on any of the member buffers, or use FOR EACH or FIND syntax to access the rows in any member table.
As an example, you can add this MESSAGE statement to the procedure DynamicMain2.p:
The code output shows you the WHERE-STRING and RELATION-FIELDS attributes for the ProDataSet's one relation:
As you can see, the WHERE-STRING of the query selects records in ttOrder whose CustNum matches ttCustomer. The RELATION-FIELDS attribute lists the fields used in the join. You can use either of these strings as a starting point, if you want, for a query of your own. The WHERE-STRING attribute is writeable, so you can either add to its value or replace it entirely. If you assign a new value to the attribute, the AVM uses the new WHERE expression when it re-opens the query during navigation to filter the child table of the data-relation.
So let us use this query to walk through the records in the ttOrder table:
DO WHILE NOT hQuery:QUERY-OFF-END:
MESSAGE hBuffer:BUFFER-FIELD(1):NAME
hBuffer:BUFFER-FIELD(1):BUFFER-VALUE SKIP
hBuffer:BUFFER-FIELD(2):NAME
hBuffer:BUFFER-FIELD(2):BUFFER-VALUE
VIEW-AS ALERT-BOX.
hQuery:GET-NEXT().
END.
This block of code retrieves the relation's query, whose join fields and where-clause you have already seen. It opens the query, retrieves the first record, and displays the first two fields in the buffer for each record that satisfies the query.
If you run the procedure with this block of code, you get nothing. Why?
The reason is that there is no ttCustomer record selected. The ProDataSet does not automatically select any records in its temp-tables. You have to set the navigation in motion with queries or find statements of your own. The ProDataSet prepares queries for dependent tables, but again, you need to use the query to actually bring records into the buffers.
If you add this next statement just before the code in the previous code example, it brings the first (and, in this case, only) ttCustomer record into that parent table's buffer:
hRelation:PARENT-BUFFER:FIND-FIRST().
Now the query for ttOrder has a proper ttCustomer.CustNum value for its own query, and you get the results you expect, as shown:
There are several other relation attributes, as shown in the following syntax:
Syntax
[ logical-var = ] relation-handle:REPOSITION.
This method returns true if the relation is a REPOSITION relation, otherwise false. It can be set to change the mode of a relation.
By default, all relations in a ProDataSet are active. You can selectively disable a relation at compile time using the Data-Relation NOT-ACTIVE option. The ProDataSet also supports a logical RELATIONS-ACTIVE attribute. To deactivate all the Data-Relations in a ProDataSet, set the attribute value to false, as shown in the following syntax:
Syntax
dataset-handle:RELATIONS-ACTIVE = FALSE.
To reactivate them, set the attribute to true.
Alternatively, you can deactivate or reactivate a relation between two buffers in a ProDataSet by setting the ACTIVE attribute on the relation handle, as shown in the following syntax:
Syntax
relation-handle:ACTIVE = TRUE | FALSE.
Setting RELATIONS-ACTIVE to false for a ProDataSet is equivalent to setting ACTIVE to false, or specifying the NOT-ACTIVE option on all relations individually. Likewise, setting RELATIONS-ACTIVE to true for a ProDataSet sets the ACTIVE attribute to true for each individual relation. The most common use of RELATIONS-ACTIVE happens when you are operating in a mode where a FILL should operate on each buffer using its own individual query, without the nested filling of a parent and its children that usually occurs otherwise. This might be done for efficiency. Setting RELATIONS-ACTIVE to false is easier than traversing the ProDataSet's relations individually. Likewise, you might want to turn all relations back on after completing a FILL so that they are used to traverse the data after it has been loaded.
When a relation is inactive, there are several changes to the default behavior of the ProDataSet, depending on whether the FILL is done on the ProDataSet handle or on one of its buffer handles.
First, during a FILL on a ProDataSet temp-table buffer, if the AVM encounters a deactivated relation as it traverses the parent-child tree starting at that buffer, it does not fill the child of that relation and does not continue down that branch of the relation tree at all. In other words, a FILL on a ProDataSet buffer fills from that buffer down, stopping at any level that has no children and at any level where the relation to a child is deactivated.
By contrast, if the FILL is done on the ProDataSet handle, then every child of a deactivated relation is treated as a top-level table and filled either according to its query definition, if it has one, or with all records from its Data-Source.
Second, if a relation is inactive during navigation of a ProDataSet, the dynamic query for the child table is not prepared or opened as parent records are selected, even if there is a browse associated with the relation's query. Any access to the child temp-table must be through a query, FOR EACH, or other standard ABL construct in the application code.
No implicit behavior occurs when a relation is reactivated. There is no automatic synchronization of the hierarchy below the newly active relation. If you want to resync related buffers when you set the ACTIVE attribute to true, you can do this with the SYNCHRONIZE method on the parent buffer. Doing a partial ProDataSet FILL to return Order headers shows examples of deactivating and activating Data-Relations.
Standard object attributes that are defined for the Data-Relation object include: