Try OpenEdge Now
skip to main content
ProDataSets
Data Access and Business Entity Objects : Data Access object : Elements of a Data Access object : Data retrieval API
 
Data retrieval API
There can be both standard and specialized API calls that populate a ProDataSet. Depending on the data in the ProDataSet, there will be different sets of data that are useful to the application. In the case of the sample Order Entity, there is a call to retrieve all data for a single Order Number and another call to retrieve summary data in just the Order table for some related set of Orders. What these calls have in common is that they require code that is "data source aware" to prepare the right queries or otherwise adjust the parameters of the FILL. For this reason, they belong in the Data Access object.
In general, it is a good idea not to allow anything except the Data Access object's Business Entity to use its API directly, so that if the user interface or some other part of the application needs to request data, it should use the API of the Business Entity, which can then turn around and use the API of the Data Access object to retrieve the right data.
In the sample procedures, there is a fetchOrder procedure that accepts an Order Number and returns a ProDataSet as output. This runs this procedure of the same name in the Data Access object OrderSource.p, passing in the Order Number, along with the Business Entity's ProDataSet instance as an INPUT-OUTPUT parameter:
PROCEDURE fetchOrder:
  DEFINE INPUT        PARAMETER piOrderNum AS INTEGER NO-UNDO.
  DEFINE INPUT-OUTPUT PARAMETER DATASET    FOR dsOrder.

  QUERY qOrder:QUERY-PREPARE("FOR EACH Order WHERE Order.OrderNum = " +
    STRING(piOrderNum) +
    ", FIRST Customer OF Order, FIRST SalesRep OF Order").
  /* Note that this reference to dsOrder is not using the local definition
     but rather the actual dataset instance being passed in. */
  IF VALID-HANDLE(DATASET dsOrder:GET-BUFFER-HANDLE(1):DATA-SOURCE) THEN
    DATASET dsOrder:FILL().
  ELSE DO:
    DATASET dsOrder:GET-BUFFER-HANDLE(1):TABLE-HANDLE:ERROR-STRING =
      "Data-Sources not attached".
    DATASET dsOrder:ERROR = TRUE.
  END.
  RETURN.
END PROCEDURE. /* fetchOrder */
The primary reason for this separation is to avoid having Data-Source-aware code, such as the QUERY-PREPARE method, in the Business Entity. If the nature of the data source ever changes, then all the references to it are captured in the Data Access object and can be changed together.
As you can see, fetchOrder requires that the caller previously run the attachDataSet method to attach Data-Sources and callback procedures. It could also be good practice to embed a check inside each API call in the Data Access object that assumes that the Data-Sources and any callback procedures are attached. The check can then run the attach function as needed, rather than depending on the caller to do this first.
For example, you could conditionally invoke attachDataSet from within fetchOrder. First you define a function prototype for attachDataSet at the top of the procedure, as shown:
FUNCTION attachDataSet RETURNS LOGICAL (INPUT phDataSet AS HANDLE) FORWARD.
Then fetchOrder can invoke the function if the Data-Sources are not attached, rather than raising an ERROR:
PROCEDURE fetchOrder:
  DEFINE INPUT       PARAMETER piOrderNum AS INTEGER NO-UNDO.
  DEFINE INPUT-OUTPUT PARAMETER DATASET    FOR dsOrder.

  DEFINE VARIABLE hDataSet AS HANDLE NO-UNDO.

  /* Note that this reference to dsOrder is not using the local definition
     but rather the actual dataset instance being passed in. */

  hDataSet = DATASET dsOrder:HANDLE.
  IF NOT VALID-HANDLE(DATASET dsOrder:GET-BUFFER-HANDLE(1):DATA-SOURCE) THEN
    attachDataSet(INPUT hDataSet).

  QUERY qOrder:QUERY-PREPARE("FOR EACH Order WHERE Order.OrderNum = " +
    STRING(piOrderNum) +
    ", FIRST Customer OF Order, FIRST SalesRep OF Order").

  DATASET dsOrder:FILL().
  /* The attach call makes the error message unnecessary.
  ELSE DO:
    DATASET dsOrder:GET-BUFFER-HANDLE(1):TABLE-HANDLE:ERROR-STRING =
      "Data-Sources not attached".
    DATASET dsOrder:ERROR = TRUE.
  END.
  */
  RETURN.
END PROCEDURE. /* fetchOrder */