Sample procedure: adding REPOSITION and SYNCHRONIZE
In Introducingthe OpenEdge DataSet you learned about the REPOSITION mode for a Data-Relation. You can include this in a DATASET definition as a keyword at the end of the relation definition, or you can set it at run time as an attribute (true or false) on the relation.
When you fill a ProDataSet, REPOSITION mode on a relation causes the AVM to treat the relation as deactivated and to populate the child table with all records from its Data-Source buffer, or with all those you specify in your own Data-Source query.
When you are navigating, REPOSITION mode causes the AVM to reposition its default query on the relation to the correct record, rather than reopening the query to select only that record.
In this section, you will extend the dsOrderWin.w example to show the effect of the REPOSITION mode on a relation. You will also use the SYNCHRONIZE method to readjust the queries the browses for OrderLines and Items use.
First, open dsOrder.i and add the keyword REPOSITION at the end of the LineItem relation definition, as shown:
DEFINE DATASET dsOrder FOR ttOrder, ttOline, ttItem
DATA-RELATION OrderLine FOR ttOrder, ttOline
RELATION-FIELDS (OrderNum, OrderNum)
DATA-RELATION LineItem FOR ttOline, ttItem
RELATION-FIELDS (ItemNum, ItemNum) REPOSITION.
Next, get the window procedure to use the relation queries rather than the static queries the AppBuilder generates. When you created dsOrderWin.w, you created two static browses to show the contents of ttOline and ttItem. The AppBuilder generated queries for the temp-tables for you when you did this, and associated them with preprocessor values, as shown:
&SCOPED-DEFINE OPEN-QUERY-ItemBrowse OPEN QUERY ItemBrowse FOR EACH ttItem
NO-LOCK INDEXED-REPOSITION.
&SCOPED-DEFINE OPEN-QUERY-OlineBrowse OPEN QUERY OlineBrowse FOR EACH ttOline
NO-LOCK INDEXED-REPOSITION.
…
&SCOPED-DEFINE OPEN-BROWSERS-IN-QUERY-dsFrame ~
~{&OPEN-QUERY-ItemBrowse}~
~{&OPEN-QUERY-OlineBrowse}
You then used the OPEN-BROWSERS preprocessor in the LEAVE trigger for the Order Number field:
{&OPEN-BROWSERS-IN-QUERY-{&FRAME-NAME}}
However, now you want to use the dynamic queries the ProDataSet provides for you so that you do not have to bother using those the AppBuilder defines.
In the Main Block of dsOrderWin.w, add these lines to associate the two browse objects with the ProDataSet relation queries:
MAIN-BLOCK:
DO ON ERROR UNDO MAIN-BLOCK, LEAVE MAIN-BLOCK
ON END-KEY UNDO MAIN-BLOCK, LEAVE MAIN-BLOCK:
RUN enable_UI.
/* Replace the default AppBuilder-generated static queries with
the ones that are part of the Data-Relations. */
OlineBrowse:QUERY = DATASET dsOrder:GET-RELATION("OrderLine"):QUERY. ItemBrowse:QUERY = DATASET dsOrder:GET-RELATION("LineItem"):QUERY. ItemBrowse:SET-REPOSITIONED-ROW(4, "CONDITIONAL").
IF NOT THIS-PROCEDURE:PERSISTENT THEN
WAIT-FOR CLOSE OF THIS-PROCEDURE.
END.
The OrderLine relation query is filtered automatically for ttOlines of the currently selected ttOrder. In the case of this sample window, there is only one ttOrder in the ProDataSet at a time. As you have seen from other examples, if there is more than one parent, the relation query filters for the current parent.
Because of the REPOSITION qualifier on the relation, the LineItem relation query does not select just the ttItem for the current ttOrder. Instead, this qualifier tells the AVM to leave the ttItem query open for all ttItem records, and to reposition it to the correct ttItem for the current ttOline.
The SET-REPOSITIONED-ROW method tells the AVM to make the selected row the fourth row in the viewport, so it is in the middle, unless it is already being displayed (that is the CONDITIONAL part).
In the LEAVE trigger for iOrderNum, you need to add statements that close the relation queries that the ttOline and ttItem browses are now using. If you do not do this, you might see anomalous behavior when they are reopened for the ProDataSet on another Order, as shown:
IF iOrderNum NE 0 THEN DO:
DATASET dsOrder:GET-RELATION(1):QUERY:QUERY-CLOSE(). DATASET dsOrder:GET-RELATION(2):QUERY:QUERY-CLOSE(). . . .
Remove or comment out the OPEN-BROWSERS… preprocessor. In addition, add a line to run the SYNCHRONIZE method on the top-level buffer, for ttOrder, as shown:
Since the two browses have been connected to the relation queries, it is not necessary to use the static ones anymore. But because there is no browse at the top level, for the ttOrder fields, you must nudge the AVM and direct it to go through the steps to reopen or reposition the related queries for the current ttOrder record. This is what SYNCHRONIZE does.
When you rerun the window procedure, you can see the effect of the REPOSITION relation:
You can scroll up and down in the ItemBrowse to see that the AVM has retrieved all Items into the temp-table. That is what REPOSITION does at FILL time. As you can see, the relation query the browse is using is automatically positioned to the correct ttItem each time you select a ttOline record. That is the part that REPOSITION does when you are navigating a filled ProDataSet. If you want one behavior without the other, you can turn the REPOSITION attribute on and off at run time.
Just to reinforce what is happening here, try removing the REPOSITION keyword from dsOrder.i again and rerunning the window:
At fill time, the AVM is loading only Items that are in one or more of your OrderLines into ttItem. When you view the data, it is filtering ttItem to show only the one ttItem for the current ttOline in the browse. So there is really nothing to browse in this case.