The DataSet Component

The DataSet Component

Instead of proceeding with the discussion of the capabilities of a specific dataset at this point, I prefer to devote some space to a generic introduction of the features of the TDataSet class, which are shared by all inherited data-access classes. The DataSet component is very complex, so I won't list all its capabilities—I will only discuss its core elements.

This component provides access to a series of records that are read from some source of data, kept in internal buffers (for performance reasons), and eventually modified by a user, with the possibility of writing back changes to the persistent storage. This approach is generic enough to be applied to different types of data (even non-database data), but it has a few rules:

There can be only one active record at a time, so if you need to access data in multiple records, you must move to each of them, read the data, then move again, and so on. You'll find an example of this and related techniques in the section "Navigating a Dataset."

You can edit only the active record: You cannot modify a set of records at the same time, as you can in a relational database.

You can modify data in the active buffer only after you explicitly declare you want to do so, by giving the Edit command to the dataset. You can also use the Insert command to create a new blank record and close both operations (insert or edit) by giving a Post command.

Other interesting elements of a dataset that I'll explore in the following sections are its status (and the status change events), navigation and record positions, and the role of field objects. As a summary of the capabilities of the DataSet component, I included the public methods of its class in Listing 13.2 (the code has been edited and commented for clarity). Not all of these methods are directly used everyday, but I kept them all in the listing.

The Status of a Dataset

When you operate on a dataset in Delphi, you can work in different states. These states are indicated by a specific State property, which can assume several different values:

dsBrowse Indicates that the dataset is in normal browse mode; used to look at the data and scan the records.

dsEdit Indicates that the dataset is in edit mode. A dataset enters this state when the program calls the Edit method or the DataSource has the AutoEdit property set to True, and the user begins editing a data-aware control, such as a DBGrid or DBEdit. When the changed record is posted, the dataset exits the dsEdit state.

dsInsert Indicates that a new record is being added to the dataset. This might happen when calling the Insert or Append methods, moving to the last line of a DBGrid, or using the corresponding command of the DBNavigator component.

dsInactive Indicates a closed dataset.

dsCalcFields Indicates that a field calculation is taking place (during a call to an OnCalcFields event handler).

dsNewValue, dsOldValue, and dsCurValue Indicate that an update of the cache is in progress.

dsFilter Indicates that a dataset is setting a filter (during a call to an OnFilterRecord event handler).

In simple examples, the transitions between these states are handled automatically, but it is important to understand them because many events refer to the state transitions. For example, every dataset fires events before and after any state change. When a program requests an Edit operation, the component fires the BeforeEdit event just before entering edit mode (an operation you can stop by raising an exception). Immediately after entering edit mode, the dataset receives the AfterEdit event. After the user has finished editing and requests to store the data by executing the Post command, the dataset fires a BeforePost event (which can be used to check the input before sending the data to the database); it fires an AfterPost event after the operation has been successfully completed.

Another more general state-change tracking technique involves handling the DataSource component's OnStateChange event. As an example, you can show the current status with code like this: