The following example demonstrates the client and server code for working with data in a dataset.

Include file for both client and server

The following include file code contains the temp-table, dataset, and data-source definitions. The file is used on both the client and the server.

/* dsOrderOrderLine.i */
DEFINE TEMP-TABLE ttOrder NO-UNDO BEFORE-TABLE bttOrder 
FIELD OrderNum AS INTEGER
FIELD CustNum AS INTEGER
FIELD OrderDate AS DATE
FIELD ShipDate AS DATE
FIELD PromiseDate AS DATE
FIELD OrderTotal AS DECIMAL
INDEX OrderNum IS UNIQUE PRIMARY OrderNum.

DEFINE TEMP-TABLE ttOrderLine NO-UNDO BEFORE-TABLE bttOrderLine 
FIELD OrderNum AS INTEGER
FIELD LineNum AS INTEGER
FIELD ItemNum AS INTEGER
FIELD Price AS DECIMAL
FIELD Qty AS INTEGER
FIELD Discount AS INTEGER
FIELD ExtendedPrice AS DECIMAL
INDEX OrderNum_LineNum IS UNIQUE PRIMARY OrderNum LineNum.


DEFINE DATASET dsOrderOrderLine FOR ttOrder, ttOrderline 
DATA-RELATION drOrderOrderLine FOR ttOrder, ttOrderline
RELATION-FIELDS (OrderNum,OrderNum).

DEFINE QUERY qOrder FOR Order.
DEFINE DATA-SOURCE srcOrder FOR QUERY qOrder.

DEFINE DATA-SOURCE srcOrderLine FOR OrderLine.

Example code on client

client.p is the procedure code on the client-side. This procedure performs the following steps:

  1. Define the temp-tables, dataset, and data-sources.

    The procedure uses an include file to define the temp-tables, dataset, and data-sources for the application. This same include file is also used on the server.

  2. Connect to the server.

    The procedure connects to the server and runs datasetProcs.p persistently. datasetProcs.p contains two server procedures that the client calls.

  3. Fill the dataset with data from the server.

    The empty, working dataset, dsOrderOrderLine, is passed as a parameter to the fillOrderOrderLinesDS procedure, which runs on the server. Upon returning to the client, the dataset is now populated with the data from the data-sources.

  4. Update some data in the dataset.

    A ttOrder record is retrieved so that it can be updated. TRACKING-CHANGES is turned on for both the temp-tables (ttOrder and ttOrderLine) in the dataset. The ttOrder record is updated with a ship date and a new ttOrderLine record is created. After the update TRACKING-CHANGES is turned off.

  5. Send the updated data to the server so it can be updated on the server.

    A changes-only dataset is prepared to send to the server. This changes-only dataset is then passed as a parameter to the updateOrderOrderLineDS procedure, which runs on the server and makes the updates.

  6. Merge the changes back into the working dataset on the client.

    After returning to the client, if there were no errors, MERGE-CHANGES is called to merge the changes back into the working dataset on the client. The client and server data are now in sync.

/* client.p */
{include\dsOrderOrderLine.i}

DEFINE VARIABLE hServer AS HANDLE NO-UNDO.
DEFINE VARIABLE hProc AS HANDLE NO-UNDO.
DEFINE VARIABLE hChangeDataSet AS HANDLE NO-UNDO.
DEFINE VARIABLE saveCust AS INTEGER NO-UNDO.

/* This is where the connection to the PASOE server would be.
   for this sample code, using hServer = SESSION */
hServer = SESSION:HANDLE.
  
RUN datasetProcs.p ON hServer PERSISTENT SET hProc.

RUN fillOrderOrderLineDS IN hProc (OUTPUT DATASET dsOrderOrderLine).

FIND FIRST ttOrder NO-ERROR.

IF AVAILABLE (ttOrder) THEN DO:

    /* Set TRACKING-CHANGES for ttOrder and ttOrderLine */
    TEMP-TABLE ttOrder:TRACKING-CHANGES = TRUE.
    TEMP-TABLE ttOrderLine:TRACKING-CHANGES = TRUE.

    /* Change the shipDate for the ttOrder. 
       This adds a record to bttOrder with the original data
       and ROW-STATE of ROW-MODIFIED */
    ttOrder.ShipDate = TODAY.
    
    /* Create a new ttOrderLine for the current ttOrder.
       This adds a record to the bttOrderLine temp-table
       with initial values and a ROW-STATE of ROW-CREATED */
    CREATE ttOrderLine.
    ttOrderLine.OrderNum = ttOrder.OrderNum.
    ttOrderLine.LineNum = 900.

    /* Turn TRACKING-CHANGES off */
    TEMP-TABLE ttOrder:TRACKING-CHANGES = FALSE.
    TEMP-TABLE ttOrderLine:TRACKING-CHANGES = FALSE.

END.
     
/* Get the changes-only dataset to send to the server */
CREATE DATASET hChangeDataSet.

hChangeDataSet:CREATE-LIKE(DATASET dsOrderOrderLine:HANDLE).

hChangeDataSet:GET-CHANGES(DATASET dsOrderOrderLine:HANDLE).
         

/* Update the data on the server */
RUN updateOrderOrderLineDS IN hProc (INPUT-OUTPUT DATASET-HANDLE hChangeDataSet).  

IF hChangeDataSet:ERROR = TRUE THEN  DO:
    MESSAGE "errors during update " VIEW-AS ALERT-BOX.
END.
ELSE DO:
    hChangeDataset:MERGE-CHANGES(DATASET dsOrderOrderLine:HANDLE).
END.

DELETE PROCEDURE hProc.

END.

Example code on server

The server code, datasetProcs.p, uses the same include file to define the temp-tables, dataset, and data-sources. The code contains two internal procedures, fillOrderOrderLineDS and updateOrderOrderLineDS. The fillOrderOrderLineDS procedure performs the initial FILL of the dataset with records from the data-sources. The updateOrderOrderLineDS procedure updates the data-sources by calling SAVE-ROW-CHANGES to validate and then update the affected records.

/* datasetProcs.p */
{include\dsOrderOrderLine.i}

PROCEDURE fillOrderOrderLineDS:

    DEFINE OUTPUT PARAMETER DATASET FOR dsOrderOrderLine.

    QUERY qOrder:QUERY-PREPARE( "FOR EACH Order WHERE ShipDate < TODAY" ).

    BUFFER ttOrder:ATTACH-DATA-SOURCE(DATA-SOURCE srcOrder:HANDLE).
    BUFFER ttOrderLine:ATTACH-DATA-SOURCE(DATA-SOURCE srcOrderLine:HANDLE).

    DATASET dsOrderOrderLine:FILL().

    /* Detach the data sources */
    BUFFER ttOrder:DETACH-DATA-SOURCE( ).
    BUFFER ttOrderLine:DETACH-DATA-SOURCE( ).

    RETURN.
END PROCEDURE.

PROCEDURE updateOrderOrderLineDS:

    /* Dataset with just the changes made on the client */
    DEFINE INPUT-OUTPUT PARAMETER DATASET FOR dsOrderOrderLine.

    /* Attach the data sources in order to save changes back to the database
       This example passes the change dataset as a dataset-handle, but using
       the static dataset makes the code simpler */
    BUFFER ttOrder:ATTACH-DATA-SOURCE(DATA-SOURCE srcOrder:HANDLE).
    BUFFER ttOrderLine:ATTACH-DATA-SOURCE(DATA-SOURCE srcOrderLine:HANDLE).

    FOR EACH bttOrder:
        
        MESSAGE "saving order row-state = "  BUFFER bttOrder:ROW-STATE VIEW-AS ALERT-BOX.
        MESSAGE "saving " bttOrder.OrderNum bttOrder.ShipDate VIEW-AS ALERT-BOX.
        
        BUFFER bttOrder:SAVE-ROW-CHANGES().
    END.

    FOR EACH bttOrderLine:

        MESSAGE "saving orderline row-state = "  BUFFER bttOrderLine:ROW-STATE VIEW-AS ALERT-BOX.
        MESSAGE "saving " bttOrderLine.OrderNum bttOrderLine.LineNum VIEW-AS ALERT-BOX.

        BUFFER bttOrderLine:SAVE-ROW-CHANGES().
    END.

    /* Detach the data sources */
    BUFFER ttOrder:DETACH-DATA-SOURCE( ).
    BUFFER ttOrderLine:DETACH-DATA-SOURCE( ).

    RETURN.
END PROCEDURE.