Release 10.1A: OpenEdge Development:
Progress Dynamics Basic Development

> ## Data management in the SBO

> The SBO can run either self-contained on a client with a direct database connection or divided between client and AppServer. Most of this section describes the divided case, because it is the more complex. In this case, the SBO has a client proxy just as an SDO does, with the same `_cl` name extension and the same use of the `DB-REQUIRED` preprocessors. The `_cl` file is generated on `Save` from the AppBuilder automatically, the same as for an SDO.

> The client-side SBO proxy contains the same logic for choosing the appropriate SDO file to run as is used by other Container objects. That is, if the necessary databases used by the SDO are not connected, the SmartContainer (in the procedure `constructObject`) will search for and run the `_cl` proxy file for the SDO. If the required databases are not connected and the SDO `proxy.r` file is not found, an error will result.

> When the client application is run, the client SBO runs as a client proxy and runs a server-side copy of itself. It supports the same AppServer properties and supporting code as the SDO to accomplish this. The server-side object in turn starts the SDOs, which in the two-layer model now have their own database connection. The client SBO proxy runs each contained SDO. All data is passed from server to client and back again through the SBO connection, not directly from the SDOs. When the client application is run with a state-aware AppServer, the client SBO initializes its temp-tables from communication with the server-side object through the SBO Container. When run with a stateless AppServer, the server-side SBO and SDO are not involved in the initialization of the client.

> Figure 11–7 illustrates an example.

> Figure 11–7: Data management example

> When you are retrieving data from the server through an SBO, you can specify a `WHERE` clause for one or more of its SDOs. The functions `assignQuerySelection` and `removeQuerySelection` are supported for SBOs just as for SDOs, and they let you modify the `WHERE` clause of any of the contained SDOs. The one restriction in the implementation of these functions for the SBO is that you must qualify column names with the `ObjectName` of the SDO, to let the SBO know which object to pass the `WHERE` clause assignment.

> Note: The `setQueryWhere` function is not supported; in any case, `addQueryWhere` and `assignQuerySelection` are more flexible ways to manipulate the `WHERE` clause.

> The SBO retrieves data from the server by running the `fetchContainedData` procedure. (This is run internally and automatically; it is not expected that application code will run this procedure itself. The `openQuery` function is provided to do this from application code to provide an interface similar to that of the SDO.) The `fetchContainedData` procedure collects the `QueryString` properties of its `ContainedDataobjects` and passes them to the server by running `serverFetchContainedData`. This server-side procedure resets the `QueryString` properties on the server, and the query for the top-level SDO specified is opened.

> The `fetchContainedData` procedure gets back as `OUTPUT` parameters the `TABLE-HANDLE`s of the `RowObject` tables and passes these on to the individual SDOs.

> When the user changes the current row in an SDO with a `Data-Target`, all rows in dependent queries are flushed from the client and replaced by the rows matching the `ForeignField` values for the new master row (with the same checking for modified rows as for independent SDOs).

> When the user changes individual rows, the rows are saved on the client (in their respective SDOs) until committed. When the user chooses the Commit button or the `CommitTransaction` event occurs in some other way, all updated rows from all updated SDOs are sent back to the server and validated there.

> If scrolling or other repositioning moves to the end of the current data set for any SDO and the entire result set has not been retrieved from the server, the next batch of rows is retrieved from the server for that SDO.

> There are two basic procedures to handle this data transfer from server to client:

> - `fetchContainedData` — Makes a call to its server-side counterpart, `serverFetchContainedData`, passing a delimited list of the `QueryString` properties of all the SDOs, and getting back a set of `TABLE-HANDLE` `OUTPUT` parameters for each SDO. These are the handles of the temp-tables of the SDOs contained in the SBO on the client side. In this way, all of the data from multiple SDOs can be requested and returned in a single call. This is different (and more efficient) than what happens with individual SDOs that are nested in a parent-child relationship. In that case, each SDO has its own connection to the server, and each makes its own independent request for data, with the `dataAvailable` events that cascade the key values from parent to child occurring on the client. With an SBO, all the data is transmitted through the single SBO connection, and the `dataAvailable` events occur on the server.

> - `serverContainedSendRows` — Takes care of retrieving additional batches of rows in the case where more than one batch is required. In general, it is expected that this will occur only when the user is browsing the top-level SDO in the SBO. However, the mechanism will also work for dependent SDOs with enough rows that they cannot all be retrieved in a single batch. The `serverContainedSendRow` procedure is run from `clientSendRows` (the existing SDO procedure) when another batch of rows is needed. The `clientSendRows` procedure determines whether it is inside an SBO by checking the new SDO property `QueryContainer`, which is true if the SDO’s container is itself a `QueryObject`. In this case, the SDO will get the ASHandle property of the container SBO and run `serverContainedSendRows` directly itself, using the SBO’s AppServer connection.

Copyright © 2005 Progress Software Corporation www.progress.com Voice: (781) 280-4000 Fax: (781) 280-4095