Access Data-Relations
- Last Updated: January 17, 2024
- 7 minute read
- OpenEdge
- Version 12.8
- Documentation
Syntax
This topic 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:
|
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:
|
Where:
- 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:
|
Likewise, PARENT-BUFFER returns
the parent buffer handle of the relation, as shown in the following
syntax:
|
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:
|
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:

|
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:
|
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:
|
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:
|
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:
|
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:
|
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:
|
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:
|
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. Do 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:
-
ACTIVE -
ADM-DATA -
CHILD-BUFFER -
HANDLE -
INSTANTIATING-PROCEDURE -
MAXIMUM-LEVEL -
NAME -
NESTED -
PARENT-BUFFER -
PRIVATE-DATA -
QUERY -
RECURSIVE -
RELATION-FIELDS -
REPOSITION -
TYPE -
WHERE-STRING