Database Engine Architecture
The three main classes comprising the Database Engine framework are CGXDBEGrid, CGXDBEngine, and CGXBrowserLayoutManager.
Figure 132 – Database Engine Class Architecture
NOTE >> NOTE: The dotted lines in the graphic above indicate that the class delegates functionality to another.
This architecture introduces the interface DBEngine (abstract base class, CGXDBEngine), which exposes an interface through which a grid can access any kind of datasource. You can bind an implementation of this abstract base class to a specific data access technology, such as Perforce’s SourcePro DB.
The APIs exposed by the engine are divided into three groups: Initializing, Fetching, and Updating.
Initializing APIs
There is no initializing API in the base CGXDBEngine class, because the parameters required for initializing typically vary in count and type depending on how you are accessing the database. The concrete implementation of the CGXDBEngine class specifies the APIs for initializing. The concrete implementation provides one-time initialization through the constructors and/or special functions to initialize/re-initialize the engine. The engine can re-initialize in three different ways.
*Requery with the same parameters, usually to get the most current version of the underlying data.
*Requery with modified parameters but the result set would have the same schema.
*Re-initialize with different parameters, with the result set having a new schema. This amounts to closing the engine and re-opening it.
The concrete implementation needs to support one or more of the techniques for reinitializing the engine. The technique you use to re-initialize the engine affects the bound grid. If you requery the grid, it redraws to refresh its state and display. If you re-initialize the grid with different parameters, a new schema is created and InitFromEngine() is called to re-initialize the grid.
Fetching APIs
Most of the database driver APIs expose the result of a query in the form of records, so you can fetch the data in the records one at a time. Although this is suitable for data-processing applications, data-presentation applications like the grid prefer the resultant data in a tabular form. Accordingly, the CGXDBEngine interface exposes a table-like API.
virtual BOOL GetValue(long nRecord, long nField, CString& strValue)
= 0; // nRecord and nField are 0 based...
virtual long GetRecordCount() = 0; // 1 based...
virtual long GetFieldCount() = 0; // 1 based...
Because the grid ultimately renders a string to the screen, it is optimal for GetValue() to return a string.
You need to fetch records for the grid incrementally. When you are working with large tables, you should fetch a minimal number of records initially and then fetch more records as necessary. Typically, more records need to be fetched when the user scrolls down to see more records. The CGXDBEngine exposes a convenient API to handle fetching records.
// Enables incremental fetching...
virtual void FetchRecords(long nRecords) = 0;
A side effect of fetching incrementally is that we do not know if the count returned by GetRecordCount reflects the total record count or only the number of records fetched so far. The following API solves that problem.
virtual BOOL IsEOFSeen() ;
Updating APIs
Unlike the fetch data, the grid likes to see update data as records rather than in tabular form. This is because the grid subscribes to the popular database editing technique of editing and updating one record at a time. The following update APIs allow such a technique.
virtual BOOL Edit(long nRecord) = 0;
// Call Edit before editing a record via SetValue...
virtual BOOL SetValue(long nRecord, long nField, CString* strValue);
virtual BOOL Update(CString* strError = NULL) = 0;
// Complete the editing on a record by calling Update...
virtual long AddRow() = 0;
// The returned value is the new record no. that should
// be used in SetValue...
virtual BOOL DeleteRows(long nFrom, long nTo) = 0;
Calling Edit() begins an edit mode on a particular record. After a record is in edit mode, you can call SetValue() on that record only. After you finish editing the record, call Update() to store the changes inside the datasource. Complete the same steps to add a new row.
Miscellaneous APIs
There are also APIs that allow you to cancel a current edit mode, ensure that the engine is initialized, ensure that the result set can be updated, requery the result set, and more. For a comprehensive listing of the APIs exposed, see CGXDBEngine in the Objective Grid Class Reference.
Summary of Database Architecture
Essentially, the logic involved in communicating with the datasource is decoupled from the grid in an implementation of CGXDBEngine. You can easily bind the grid with your datasource by implementing the simple interface specified in the abstract CGXDBEngine.