The DataSet class hierarchy is the centerpiece of the DataExpress architecture.
The DataSet class hierarchy is not a set of implementable interfaces. DataSets provide a rich level of functionality and semantics for data access and update. If interfaces existed for these APIs, the implementor would have the burden of supporting the rich functionality and semantics of the DataSet APIs. The intent of the DataExpress architecture is to provide a powerful, performant, and tested set of components that are ready for use and customization. Customization is achieved by property settings, event handlers, and implementation of smaller, more focused interfaces such as Resolver and DataFile (both discussed later).

The DataSet class hierarchy is not a set of implementable interfaces. DataSets provide a rich level of functionality and semantics for data access and update. If interfaces existed for these APIs, the implementor would have the burden of supporting the rich functionality and semantics of the DataSet APIs. The leaf nodes of this class hierarchy are instantiable components. DataSet and StorageDataSet are abstract classes.
DataSet. An abstract class. A large amount of the public API for all DataSets is surfaced in this class. All navigation, data access, and update APIs for a DataSet are surfaced in this class. Support for master detail relationships, row ordering, and row filtering are surfaced in this class. All of our data, aware JBCL controls have a DataSet property. This means a GridControl can have its DataSet property set to the various extensions of DataSet: DataSetView, QueryDataSet, ProcedureDataSet, and TableDataSet.
StorageDataSet. An abstract class. The StorageDataSet manages the storage of DataSet data,indexes used to maintain varying views of the data and persistent Column state. The current release provides efficient in-memory storage for data. The architecture also lends itself to plugging in persistent DataStores as well. All structural APIs (add/delete/change/move column) are surfaced in this class. Since StorageDataSets manage the data, it is where all row updates, inserts, and deletes are automatically recorded. Since all changes to the StorageDataSet are tracked, we know exactly what needs to be done to save (resolve) these changes back to the data source during a resolution operation.
DataSetView. This component can be used to provide independent navigation (a cursor) with a row ordering and filtering different than that used by the base DataSet. To use this, component DataSetView has a StorageDataSet property that must be set. This component can also be used when multiple controls need to dynamically switch to a new DataSet. The controls can all be wired to the same DataSetView. To force them all to view a new DataSet, the DataSetView StorageDataSet property can be changed.
QueryDataSet. This is a JDBC-specific DataSet. It manages a JDBC provider of data. The data to be provided is specified in a query property. The query property is a SQL statement.
ProcedureDataSet. This is a JDBC-specific DataSet. It manages a JDBC provider of data. The data to be provided is provided with a procedure property. The procedure property is a stored procedure.
TableDataSet. This is a generic DataSet component without anya built-in provider mechanism. Even though it has no default provider, it can be used to resolve its changes back to a data source. TableDataSets Columns and data can be added through DataSet methods or by importing data with a DataFile component like TextDataFile.
1.2 The Column component.
A StorageDataSet can contain one or more Column components. A Column describes data type, meta data, and several persistent properties (constraints, defaults, etc.) for a column in a DataSet. Unlike Delphi Field components, data values are notcannot be retrieved from a Column object. Instead, field values are retrieved through DataSet and Read/ReadWriteRow methods. The reason for this difference is that DataExpress DataSets allow for multiple views (via DataSetView) with separate cursors of the same StorageDataSet.
Columns can also be marked persistent. Since several properties can be set on a Column, including display/edit masks, constraints, defaults and validation events, it is useful to persist Columns for a DataSet. This is most easily done interactively. Columns can be added and marked persistent in the JBuilder visual component tree, simply by editing any of their properties.
Another valuable use of Columns is to persist meta data for QueryDataSets and ProcedureDataSets. When providing data for a QueryDataSet, meta data discovery is performed. The needed meta data is usually very basic: Table name, column names, column data type, unique row identifiers, precision, and scale. If for some reason the driver cannot provide this information, or retrieval of this information is slow, the meta data can be specified in a persistent Column.
1.3 The DataModule.
This is similar to the Delphi DataModule. The DataModule is a nonvisual container for components. It is especially well-suited to containing collections of related DataExpress components (i.e. DataSets and Database components). Although the DataModule is not visible at runtime, it is visible and designable in the JBuilder VCD component tree. Although other containers like Frames and Applets can contain database-related components, it is generally a much better practice to centralize related database components into a DataModule. This allows the developer to separate business rules and application logic from components that are largely used for visual presentation (i.e. Frames and data-aware controls). The DataModule also allows for easier reuse of the components it contains. This is because a DataModule can be reused by multiple Frames or Applets.
The best way to create a DataModule is to use the DataModule Wizard in JBuilder (File|New). This will create the basic skeleton of a DataModule. There are two ways to reference a DataModule inside another Frame or Applet. The easiest way is to add a statement in your visual container that creates a new instance of your DataModule:
MyDataModule myDataModule = new MyDataModule();
The drawback to this is that there is that this instance is not easily referenced by other visual containers. The solution to this problem is to call a static method in your DataModule that instantiates the DataModule for the first caller and returns this same instance to any successive callers:
MyDataModule myDataModule = MyDataModule.getDataModule();
You don't have to implement the getDataModule method yourself; the DataModule Wizard does this for you.
1.4 The Database component.
This is a JDBC-specific component that manages a JDBC connection. QueryDataSets and ProcedureDataSets have a Database property. Multiple DataSets can share the same Database. The Database Connection property specifies the JDBC connection url, user name, password, and optional JDBC driver(s). The JDBC connection url is the JDBC method for specifying the location of a JDBC data provider (i.e. SQL server). It can actually contain all the information for making a successful connection, including user name and password.
1.5 Descriptor properties.
There are several property names that end in "Descriptor." For better readability, the property inspector does not show "Descriptor" in the property name, but the generated code does. These are simple containers for groups of related properties that usually have customized property editors. SortDescriptor (sortkeys, caseInsensitive, descending) and QueryDescriptor (database, query, paramRow, executeOnOpen, asynchronousExecution) are examples of this practice.
1.6 Row classes.
Though not shown in the hierarchy diagram above, the DataSet class actually derives from some row classes. The row hierarchy looks like this:
ReadRow. This is an abstract class that provides read access to a row of data. There are getters for the data types supported by JDBC standard. Data values can be accessed by ordinal or by name. There is also a method for copying one row to another.
ReadWriteRow. This is an abstract class extension of ReadRow that provides read and write access to a row of data. There are getters and setters for the data types supported by the JDBC standard. There is also a method for setting default values and applying constraints.
DataRow. This is a class that can be instantiated. Its constructors require at least a DataSet. The associated DataSet defines the number and type of columns. The DataRow has one row of storage that can be set and fetched. A DataRow can be scoped. A scoped DataRow is constructed by using the constructor that has a DataSet and String array argument. The String array is an array of Column names in the DataSet. A DataRow will only allow setting and fetching of the Columns it is scoped to. A scoped DataRow is useful for locate and lookup operations. The locate mechanism will only search on the columns specified in the scoped list of columns.
DataSet. This is the same abstract class discussed in the DataSet hierarchy. As an extension of ReadWriteRow, the row of data being accessed by the ReadWrite methods is the current row that the DataSet is positioned to. So if you navigate to the 5th row and do a get operation, the values returned will be whatever is at the 5th row.
ParameterRow. This is a class that can be instantiated. It contains one row of storage. Unlike DataRow, it gets its columns from add/setColumns() methods. It is used for parametized queries and procedures. The reason that DataRow cannot be used for query/procedure parameters is that there may be multiple parameters for the same column. An example of this would be a where clause that compared a column value to a start-and-end parameter. In this case, two parameter columns are needed for one data column.
The Row classes are used extensively in the DataExpress APIs. The ReadRow and ReadWriteRow are used much like interfaces that indicate what the usage intent is. By using a class hierarchy, implementation is shared and there is a slight performance advantage of not using interfaces.
The Row classes provide access to column values by ordinal and column name. Specifying columns by name is a more robust and readable way to write your code. Accessing columns by name is not quite as quick as by ordinal, but it is still quite fast if the number of columns in your DataSet is 20 or less, due to some patentedproprietary high-speed name/ordinal matching algorithms. It is also a good practice to use the same Strings for all access to the same column. This saves memory and is easier to type in if there are many references to the same column.
Variant class.
This class is unique to the Borland JBCL and is used to map JDBC type system into its internal type system. There is a mapping of JDBC types to Variant types. A Variant object can store any of the Variant Types. The DataExpress architecture makes extensive use of Variant for internal purposes. Although Variant is surfaced in some of the public methods of DataExpress components, most applications don't have to use Variants. There is an extra step to using a Variant because a Variant must be allocated before a public method can be called with it. Variants can be useful when you want to pass arbitrary data values across API layers.
Variant also supports two null states: Variant.ASSIGNED_NULL and Variant.UNASSIGNED_NULL. This differentiation is useful if a DataSet is resolved back to a JDBC connection. If a value is Variant.UNASSIGNED_NULL, new rows will be inserted without specifying the values for the columns that are set to Variant.UNASSIGNED_NULL. This causes many servers to fill in default values for these columns. If the value for a column is Variant.ASSIGNED_NULL, then new rows will be inserted specifying that the values of these columns should be set to null. If a row is added without setting column values, they automatically get stored to the DataSet as Variant.UNASSIGNED_NULL
Connect with Us