The dbExpress framework (DBX framework) is a set of abstract classes provided in the unit DBXCommon. Applications can interface with the framework in several ways: using the framework directly for both native and managed applications, and using the dbExpress VCL components that are layered on top of the framework for both native and managed applications.
Although many applications interface with dbExpress drivers via the dbExpress VCL components, the DBX framework offers a convenient, lighter weight option to communicate with a database driver. You can also create a database driver for dbExpress by extending the frameworks's DBXCommon abstract base classes. The DBX framework provides most commonly needed database driver functionality for a "set" oriented database application, yet provides a simple interface.
Here are some of the key features of the DBX framework:
- The driver framework is written entirely in Delphi and allows drivers to be written in Delphi.
- It uses strongly typed data access instead of pointers. For instance, it uses String types rather than pointers to strings.
- The driver framework is single sourced. You can compile the source with the native DCC32 compiler.
- The framework has only Abstract base classes that are used for drivers, connections, commands, readers, and so on.
- The framework uses exception based error handling rather than returning error codes.
There are two categories of drivers that extend the classes in DBXCommon: DBXDynaLink and DBXDirect. These drivers differ from each other in the way they are loaded and the capabilities they provide to an application. These are described in greater detail later.
You can also extend the DBX framework to write delegation drivers, which provide an extra layer between the application and the actual driver. Delegate drivers are useful for connection pooling, driver profiling, tracing, and auditing. Another possible application of driver delegation is to create a thread safe driver delegate. Such a delegate could provide thread synchronized access to all public methods.
Absolute thread safety is left to applications using dbExpress. However, some thread safety issues are best handled by the dbExpress framework. dbExpress thread safe operations include loading and unloading drivers, and connection creation. As mentioned earlier, a delegate driver can be created to make the entire public interface of dbExpress thread safe if needed.
A dbExpress driver can statically or dynamically link drivers built as Delphi packages. The easiest way to link a driver package is to just include it in the "uses" clause. The driver loader also loads packages specified in a config or ini file using the LoadPackage method. This allows dynamic loading of drivers that are never specified in a uses clause of any of the application's units. Note that the LoadPackage approach can only be employed for applications built to use packages.
dbExpress driver writers should examine the initialization sections of the DBXDynalink and DBXTrace units in the source code provided with dbExpress. These sections register themselves with a singleton unit called the ClassRegistry. The ClassRegistry is used by the dbExpress driver loader to instantiate driver loader classes by name (a String). The ClassRegistry is a simple, lightweight mechanism for registering and instantiating a class by name.
DBXDynalink is used for existing dbExpress drivers as well as new drivers. It is compiled as a native Delphi package. DBXDynalink loads native dbExpress drivers that implement a more primitive "native" interface called DBXExports. The DBXExports interface is a small collection of "flat" export methods. DBXExports's source is included with dbExpress. DBXExports provides a more strongly typed API than the dbExpress 3's COM based interface. This allows methods to be added in future product generations without breaking compatibility with older implementations of the DBXExports interface.
DBXAdapter is a dbExpress compliant driver that adapts the DBXExports interface to the older dbExpress COM interface. Newer native drivers can be written by implementing DBXExports directly.
Because the DBXExports interface is designed to be implemented using any native language (Delphi or C++), it uses more primitive, non-exception based error handling. DBXDynalink maps error codes to a DBXCommon exception.
The DBXDynalink unit contains a dbExpress driver. This driver delegates to non-Delphi drivers that implement the DBXDynalinkExport flat export interface. DBXTrace is a delegate driver used for tracing. The dbExpress VCL uses DBXCommon, DBXDynalink and DbxTrace as "default" drivers. However, this can be changed for statically linked applications without modifying dbExpress VCL source code (SQLExpr.pas). SQLExpr.pas uses the unit DBXDefaultDrivers. The DBXDefaultDrivers unit only contains a uses clause. The DBXDefaultDrivers uses clause contains DBXCommon, DBXDynalink, and DBXTrace. DBXCommon must always be used. However, a statically linked application could remove DBXTrace and replace DBXDynalink with a different driver.
A DBXDirect driver is any driver that is implemented by extending the DBXCommon abstract base classes. These classes are written in Delphi for native implementations.
Strictly speaking, all DBX framework drivers are a form of DBXDirect driver. However DBXDynalink and DBXRemote provide a more "indirect" linkage to driver implementations.