Create a data access procedure for the Order ProDataSet
- Last Updated: February 11, 2026
- 5 minute read
- OpenEdge
- Version 13.0
- Documentation
The first step is to create a data access procedure that handles all the
code that requires knowledge of the data source. To do this, you create a procedure to act
as the data access object for the dsOrder ProDataSet in the
same way that CodeSource.p does for the code table
ProDataSet from the previous . The following figure illustrates:
- Data definitions and logic to consider as part of the data access object.
- The data access object encapsulates all database references. Therefore, query definitions are part of the object.
- Data-Source definitions that map database tables and queries to ProDataSet buffers are part of the object.
- Methods (internal procedures or functions) that attach and detach Data-Sources for the ProDataSet buffers are part of the object.
- Methods that prepare database queries or methods that in other ways
reference database table and field names directly are part of the object. For example, one
kind of request of the
OrderProDataSet is to return all the data for a particularOrdernumber. This request can be made of the higher-level business entity (as you will do later), but the query itself should be prepared in the data access object. This is because that request requires defining a particular database query to get the rightOrderfrom the database. -
FILLevent logic that determines the final form of what is in the ProDataSet is part of the object. TheseFILLevent procedures can be associated with the ProDataSet instance at the time of theATTACH, as in these examples.
In
this way, all the definitions and code that reference the database
are nicely captured in a single place. Here they can be maintained,
as needed, when database definitions or data sources change. All
the higher levels of access to the ProDataSet do not contain any
such references, which isolates them from the specifics of the Data-Sources.
Once the FILL event procedures have been associated
with the caller's ProDataSet instance and the Data-Sources attached
to it, the caller can simply execute the FILL method,
and all the required logic is executed properly on that instance. The
following figure is an example.

So, let us create the data access procedure OrderSource.p.
Much of the code in this procedure comes from the OrderEvents.p procedure in Advanced Events and Attributes. You can copy code from there and adapt it as needed. The purpose of this exercise is to begin to isolate the code better, based on what role it plays, to begin to provide more of an architecture to the application's objects.
In this example, the data access procedure has a static definition of the ProDataSet and its temp-tables:
|
As we noted in Advanced Events and Attributes, it can help you isolate your ProDataSet
definitions better if you can avoid this, but if there are many
references to ProDataSet tables and fields in the FILL logic
or elsewhere, then this might not be practical. This example shows
the alternative of having the definitions in the data access procedure
so that they can be referenced in static ABL statements. As we work through
the procedure, it will be important to note how the actual ProDataSet instance
the code is operating on is not the one that this procedure
gets by including the definitions. The support code is always using
the instance from the requesting procedure.
The top-level definition and the Data-Source definitions will be familiar from OrderEvents.p. For example:
|
OrderEvents.p was intended
to run as a stand-alone procedure with no internal procedures. Thus,
it took the Order Number and OUTPUT ProDataSet
as parameters directly. In this case, the data access procedure
runs as a persistent procedure, so it has no parameters. Instead,
there is an internal procedure, called fetchOrder,
that implements this specific request for a single Order.
Because it takes dsOrder as an INPUT-OUTPUT parameter,
passed BY-REFERENCE, it is the caller's instance
of the ProDataSet that is used, not the one represented by the include
files at the top of OrderSource.p.
The
procedure uses the QUERY-PREPARE method to get
the right order, and then fills the ProDataSet, as shown:
|
The calling procedure runs the attach method
(defined later) before running fetchOrder, so that
everything has been set up properly for the FILL.
The code checks to make sure that there is a Data-Source for the
top-level buffer before proceeding with the FILL.
If not, it sets the ERROR attribute for the ProDataSet
and an error message on the top-level temp-table, which the caller
can inspect.
Later you will write another procedure that represents the Order entity itself. This will have the ProDataSet instance that
is actually used in the application, and it will define the API that other procedures, such
as a client window, would use to access the ProDataSet. That API will include a fetchOrder procedure.
Why,
then, is this version of fetchOrder here in the data
access procedure? Since it needs to use a specific database query
to prepare the top-level table, it is better to put the procedure
into the data access object. The fetchOrder procedure
in the Order entity itself will turn around and
run this one to maintain the right level of encapsulation in the
objects.
Two of the FILL event procedures
from OrderEvents.p are preserved here, postOlineFill and postItemRowFill.
Procedure postOlineFill calculates the OrderTotal in
the ttOrder table. For example:
|
Procedure postItemRowFill edits
the ItemName field in the ttItem table. For
example:
|
There is something important to note about these
two procedures. They contain direct references to fields such as ttItem.ItemName,
which is possible because the temp-table definitions are included
in the procedure. But remember that the local instance of the ProDataSet
and its temp-tables is used for definition only. When the AVM invokes
these procedures during the FILL, it passes in
the current ProDataSet instance implicitly BY-REFERENCE.
The AVM not only adjusts all references to the ProDataSet itself
to point to that external ProDataSet, but also all references to
its temp-tables and their fields. This gives you the best of both worlds,
as it were: a local static definition that makes the code simpler
and clearer, but an automatic reference at run time to an externally
defined ProDataSet that is passed into the procedure without any
copying or other overhead.
The code to attach the Data-Sources
has been separated out, however, so that it can be executed not
only for a FILL but also on a save. This is in
the function attachDataSet, which also runs the SET-CALLBACK-PROCEDURE for
the two FILL events. For example:
|
There is also a corresponding detachDataSet function.
For example:
|