skip to main content
OpenEdge Development: AppBuilder
Data-Access Objects : SmartDataObjects
SmartDataObjects (SDOs) are modular data pumps that incorporates ADM Smart technology. They communicate in a loosely coupled way with other ADM SmartObjects using SmartLinks, and with objects on the Web using WebSpeed. They can also function in an Open4GL environment with non‑ABL objects. SDOs are supplied for your use in both dynamic and static forms.
Static SmartDataObjects
Static SDOs act as custom data pumps, each producing and managing a specific data stream based on the terms of a specific query. You define a base version of that query within a master version of the object at design time.
Depending on your business needs, you can also define and add custom validation routines to the master object. These validation routines can operate at various levels of granularity, from a single field to a whole transaction. Once you have the master defined, you can then use instances made from it as often as you like.
When you compile such a static SDO, the Compiler creates two different versions of the executable r-code. One represents the complete object, usable in any context. The other is a stripped-down, client-only version. Figure 26 illustrates this process.
Figure 26: Compilation of an SDO
The stripped-down version (identified by _cl in the filename, for example: dTest_cl.w) will load whenever there is no local database connection. A _cl object expects to cooperate with the complete version of the same object loaded as part of an AppServer partition.
You can associate business rules or any other required logic with the object by writing the necessary code.
Dynamic SmartDataObjects
The dynamic version of the SDO is designed particularly for distributed use.
A static client-side SDO can only deal with one particular data stream—the specific data stream being supplied by its counterpart on the server. This is a limitation that can be significant where many such streams are involved, if the client-side objects are not stored locally. The OpenEdge WebClient is one such case—it is designed to be downloaded for use over a wide-area network such as the Internet. (See OpenEdge Deployment: WebClient Applications, for detailed information about downloading and using the new WebClient.)
The dynamic SDO solves a large part of this problem.
The dynamic object acts as a generic, general-purpose data pump. It is not limited to handling a specific data stream, as a static SDO is. The dynamic object automatically cooperates with any static, server-side SDO and can be attached to any client-side display object such as a SmartDataBrowser or SmartDataViewer.
These broad capabilities come at the cost of client-side customization.
Because it is designed to handle a data stream of any composition, you cannot enhance the dynamic SDO with custom routines. This is true even of custom validation procedures. You can add custom client-side validation routines to the static object, if you choose, but you should remain aware that all such custom routines will actually run in the static object on the AppServer, not on the client.
Since any SDO is only a data pump, you must connect its data stream to other modules for display or manipulation. Those other objects can take a number of forms, both OpenEdge and non‑OpenEdge. You define and create them separately from the SDO.
Creating a SmartDataObject master
The individual static SDOs you employ as building blocks in your application are instances of one or more master objects. Using the AppBuilder’s SDO design wizard, you can create any number of masters that produce different data streams based on the queries you define in them.
Design considerations
Before you start the SmartDataObject Wizard, you should consider these questions:
*Will you need to define a temp-table first to reduce the amount of processing? Large quantities of data can affect performance. If your application must repeatedly traverse a very large database, you might get a significant performance increase by first subsetting to a temp-table, and then operating on that subset instead.
Note that although the wizard will allow you to define such a temp-table, and will allow you to assign it as the SDO’s data source, you must write the code by hand that actually locks and copies records from the permanent table. This population step must take place before you give the SDO access to the temp-table at run time, if the rest of your application expects to find records in the table.
*What databases and tables do you want this SDO to use? This base query can be refined or sorted at run time.
*What fields do you want to expose to client objects, and what properties (such as read‑only) do you want to set for each data element?
*What are your plans for validating data on the client side (the user interface side) and the SDO side? See the “Data validation limitation” section for a discussion of an unusual and potentially important issue.
Creating the master
AppBuilder’s SmartDataObject Wizard leads you though creating an SDO master.
To create an SDO master:
1. Click the SmartDataObject in the Object Palette. The Choose SmartDataObject dialog box appears.
2. Click New. The SmartDataObject Wizard appears:
3. Click Next. Page 2 appears:
4. The SDO supports an external super procedure that allows you to encapsulate business logic called the data logic procedure. You can reuse this data logic procedure or specify a unique data logic procedure for each SDO. Activate the Use SDO logic procedure to indicate you want to use a data logic procedure. Specify the appropriate template in the Use template field and the procedure name in the Logic procedure file name field.
5. Click Next to move to Page 3:
6. If this SDO will operate on one or more temp-tables, click Define Temp-Tables to open the Temp-Tables Maintenance Editor. Using the editor, define the temp-tables this SDO will use. See the “Temp-tables maintenance” section for information about how to use the editor.
7. Click Define Query to start Query Builder. Define the base query this SDO will use. See the “Defining and editing queries using Query Builder” section for information about how to use Query Builder.
Note: The option to create a free‑form query is not available to you at this stage. If you need or want to create a free‑form query, you must create a placeholder using Query Builder and then edit the query after the wizard completes. See the “Editing a SmartDataObject master” section for further information.
When you finish with Query Builder, you will see displayed on Page 3 the text of the query you just created.
8. Click Next to go to Page 4 of the wizard:
9. Note that at this point, the list of fields is empty. Click Add Fields to start the Column Editor, and use the editor to select the fields that you want to make available through this SDO.
When you return from the Column Editor, the list will be populated with the fields you have chosen, as shown:
For information about how to use the Column Editor, see the “Selecting database fields for browsing” section.
10. Click Next to advance to the next page. If you successfully defined a database query and the related SDO RowObject temp-table fields, the Congratulatory screen displays. (If not, press the Back button and make any necessary changes.)
11. Click Finish to dismiss the wizard and reveal the new SDO master:
12. Choose FileSave and give the new master a descriptive filename. Note that, by convention, SDO filenames begin with “d”.
The new SDO master is now available for your use.
Note, too, that AppBuilder actually creates two different forms of the master. If you were to give it the name dExampleSDO and then check the file system, you would see the following:
*A standalone version, named dExampleSDO.w. This version is loaded whenever there is a local database connection. AppBuilder creates it with the DB-REQUIRED preprocessor value set to YES, since it should not load if there is no database connection.
*A client‑side version, named dExampleSDO_cl.w. AppBuilder creates it with DB-REQUIRED set to NO. This version is loaded when there is no local database connection, on the presumption that the application is running in client/server mode and the database is resident on the server side. This version is compiled with all DB-REQUIRED internal procedures stripped out, which can create a problem. See the “Data validation limitation” section for further information.
Editing a SmartDataObject master
Any modular system must have and enforce strict data‑exchange requirements if it is to avoid possible data corruption. Although you can always update your SDO masters to reflect your changing needs, you must also update any other master objects that share data with them. Furthermore, you must sometimes update all the masters in a specific order if you are to avoid breaking the signatures on which data communication depends. For more information about making data‑stream changes successfully, see the “Making changes to the data stream” section.
To edit an SDO master:
1. Choose FileOpen and select the main source file (for example dExampleSDO.w, not the dExampleSDO_cl.w client‑only file). The SDO appears:
2. Double‑click on the object. The SDO property sheet dialog box appears:
3. Click Query to edit the existing query, if necessary. See the “Defining and editing queries using Query Builder” section for information about how to use Query Builder.
4. Click on the Fields button to modify the original fields and their attributes. See the “Selecting database fields for browsing” section for information about how to use the Column Editor.
5. Save your changes.
Creating a SmartDataObject instance
Once you have an SDO master designed that will supply the data you need, you can re‑use it indefinitely. Because of the way AppBuilder checks for opportunities to create SmartLinks, you will probably find it good practice to select and place your SDO instance before you place the instances of the SmartObjects that will communicate with it.
To use an SDO in your application:
1. Open the Choose dialog box by clicking on the SmartDataObject tool icon in the Object Palette. When the dialog box opens, select the appropriate SDO master from the list:
If you have difficulty remembering which SDO master is which, choose Preview to open a dialog box that displays the fields listing for the selected master:
2. Position the new instance (created automatically when you chose the master) anywhere you like in your smart organizer workspace, and click to release. The following is the design‑time representation you will see:
3. AppBuilder will now automatically look for opportunities to create SmartLinks between it and other SmartObjects in the same organizer context. If it thinks it has found such an opportunity, an Advisor window opens. The example shown here presumes that you had previously placed a Navigation SmartPanel:
If the suggested link seems appropriate for the needs of your application, click OK. If you decide later to make changes, you can easily revise the linkage using the SmartLinks Editor. For more information the SmartLinks Editor, see the “SmartLinks editor” section.
4. Set the properties of this SDO instance. See the “Configuring a SmartDataObject instance” section for further information.
5. Save your work.
Configuring a SmartDataObject instance
Every SDO instance has a number of default properties you might wish to change. Two of the most important are:
*Determinism — By default, every instance represents a particular master object with a defined behavior. Sometimes, it might be more appropriate to treat the instance as a placeholder at design time, and conditionally load a particular SDO under program control at run time. The possible applications for this are numerous.
*Statelessness — By default, SDOs do not bind their AppServer session unless the AppServer Broker is configured to run statefully, with session‑long connections. If the AppServer Broker is running in stateless (connectionless) mode, so will the SDO. Statelessness allows many more clients to share the available AppServer sessions. The cost is an increase—typically small—in the time it takes to re‑establish connection for each request. To avoid this time penalty in selected cases, you can choose to force the SDO to bind its session and operate statefully.
To configure the SDO instance:
1. Right-click on the instance and choose Properties. The Property Sheet dialog box appears:
2. Change the Object identifier to one that more accurately reflects the role of this SDO in your application.
3. If you wish to use the object as a placeholder, see the “Creating a SmartObject placeholder” section.
4. Click OK.
5. Right-click on the instance, and choose Instance Properties. The following dialog box appears:
6. Set the properties and click OK. For more information on the properties, see the online help.
Selecting database fields for browsing
When you create an SDO master, you can access Column Editor with the Fields button on the SDO property sheet. Using the Column Editor, you can choose fields to be displayed by the browser object, impose an ordering, and define other characteristics, as shown:
Creating calculated fields
Very often, when creating applications, you will want to present a field to the user that is the result of some transformation applied to one or more other fields. Current value of inventory is one possible case, and invoice line‑item total is another. The number of such potential uses is large.
The Column Editor allows you to create such calculated fields in a straightforward way.
To create a calculated field from the Column Editor’s dialog box:
1. Click the Calculated Fields button. The Calculated Field Editor dialog box appears:
2. Compose the expression whose result will appear in the field. You can compose by typing directly into the field, by double‑clicking on tokens (Fields, Functions, Operators), or by some combination of these two methods. The expression can be of any complexity. Click OK when the expression is complete. The dialog box closes.
3. The newly defined field appears in the list of fields with the default identifier CALC, a default type of CHARACTER x(8), and no label. Change the identifier to one more meaningful in the context of your application. Add a label, if appropriate.
4. Change the data type and format, if necessary, to reflect the nature of the data. For example, if the expression yields a floating‑point result, change the data type to DECIMAL and the format string to one that portrays DECIMAL values.
5. If appropriate, click Advanced and enter a Help string for this field.
6. Use the Move Up/Down buttons to put the new field into the correct relationship to the other fields that will display.
Note: Calculated fields are created in a not‑updatable state. Although you can set them to be updatable, in general you should not: a calculated field is a scratch field, and is undefined in the context of the database. It can be easy to forget this. If you do choose to make a calculated field updatable, you must write the code yourself that will interpret any changes that a user makes.
Data validation limitation
You can choose to add data‑validation procedures to your SDO. These optional procedures can operate at the column, row, or transaction level. If you do choose to create such routines, you must create them as internal procedures. Because the SDO calls these procedures automatically, you must follow the expected naming and error‑handling conventions. See OpenEdge Development: ADM Reference for details.
SDOs have the DB-AWARE flag set. For DB-AWARE objects, AppBuilder sets the DB-REQUIRED flag in all new internal procedures, including validation procedures. Generally this is appropriate and useful. In one specific set of circumstances, however, it is not, and you will have to explicitly turn off the DB-REQUIRED flag. Those conditions are as follows:
*The application will run on an AppServer. Applications that do not run on an AppServer are not affected. Note that good practice suggests that you always design for the greatest flexibility of use.
*The client program does not require a local database connection through an SDO. Client programs that must have such a local connection in order to run are not affected. Note that good practice suggests that you always account for the case of no local connection.
*Your routines validate rows or columns (fieldnameValidate(), RowObjectValidate()). Routines that validate whole transactions (TransactionValidate()) are not affected.
The problem comes about because all DB-REQUIRED routines are removed from the client‑only version of the SDO during compilation. This allows the program to load and run in the absence of a database connection. If your validation routines are marked DB-REQUIRED, then they, too, will be removed.
Normally, calling a non‑existent routine would cause a run‑time error. But calls to optional routines never complain if they fail, and validation routines are always optional. The net result is that, when the client‑only object is loaded, database updates are carried out without client‑side validation checks even though you wrote the routines to perform them. Neither the compiler nor the interpreter can detect this logical error.
Solving the problem
The following guidelines will help you avoid errors:
*Divide your validation tasks according to whether they require a database lookup operation. References to RowObject or other temp-tables do not count as lookup operations.
*Write your fieldnameValidate() and RowObjectValidate() procedures to include only the validation operations that do not require lookup. Do not include direct references to a database in these procedures, and turn off the DB-REQUIRED flag in them. AppBuilder offers a convenient option in the Section Editor for this purpose.
*Put any validation operations requiring lookup into one of the TransactionValidate() procedures. Keep the DB-REQUIRED flag turned on in these procedures.
By writing your fieldnameValidate() and RowObjectValidate() procedures such that you can legitimately turn off the DB-REQUIRED flag in them, you ensure that these routines will survive compilation and that all validation will occur as you intend.
Forcing server‑side validation
It is generally more efficient to do row and column validation on the client side, as part of SubmitRow(). There are some cases where this is not possible—such as calling an SDO from a Java program where no client-side version of the object exists. You would then want to force all validation, including row/column validation, to take place on the server. You can do this with a single line of code.
This code also works in the case where there is a client. In that case, the client‑side validation operations take place first on the client side, and then a second time on the server side. This introduces some inefficiency, but is not otherwise harmful.
To force all validation to take place on the server, regardless of whether it also takes place in the client:
1. Open your SDO master for editing. It will appear on your display, as shown:
2. Choose WindowCode Section Editor, and then select Procedures from the sections list.
3. Create a new procedure called initializeObject()—or edit the existing procedure by that name, if you already created it—and include the following line in the procedure:
DYNAMIC-FUNCTION( ’setServerSubmitValidate’, yes ) .
4. Save your work.
All instances made from the SDO master you just changed will now perform all row/column validation on the client side—if there is a client—and on the server side too.
Using the dynamic SmartDataObject
In a situation involving an AppServer, part of the application runs on the client and part on the AppServer. Dividing the application in this way is done almost automatically—the only special thing you do is identify the AppServer partition at design time.
Changing your application to use the dynamic SDO is a one-step process: once your application is complete, move the _cl file (for example: dSample_cl.w) out of the PROPATH search space. If you are certain you will never want to use the static version on the client side, you can delete it. Otherwise, move it to a safe backup location.
That is all you need to do. If the _cl file cannot be found at run time, the dynamic object will be loaded and used instead.
Caution: The static SBO (see the “SmartBusinessObject” section for information about that object) does not support the dynamic SDO. Generally speaking, you will get the best results if you create separate SDOs for standalone and SBO use. If you must use the same SDO in both an SBO and in a standalone context, do not move or delete the _cl file. If it cannot be found during initialization of the SBO, initialization will fail and the SBO will not run.