Skip to main content

Example: Changing Selected Records in Bound Mode

  • 4 minutes to read

In bound mode, the data controller (TcxDBDataController) represents data from a TDataSet object. The data controller does not provide methods to change values of specific record fields in bound mode. You have to use your dataset’s methods or delayed updates to modify values.

The first approach can be used when you need to modify values of a single record. You can move the cursor to a dataset record and then change field values using the TDataSet.FieldValues property, for instance. When synchronization between the data controller and the dataset is enabled, the focused record identified by the FocusedRecordIndex property corresponds to the active dataset record. So you can use FocusedRecordIndex to move the dataset’s cursor to a specific record.

Changing value(s) of specific field(s) can hide the current dataset record (if filtering is enabled) or change the record position. This leads to reloading data by the data controller and clearing the selection, if any. A safer approach to modify selected records is to use delayed updates. The idea is to store the key field values of selected records and use them later to locate and modify the records.

As a rule, a dataset contains key field(s), which can be used to uniquely identify any dataset record. Key field values can be obtained by using the GetRecordID function. In order to use this function, you should assign the key field name(s) (OrderNo, in this example) to the data controller’s KeyFieldNames property.

The following example shows how to modify the SaleDate field values of selected records in a tvOrders view of the ExpressQuantumGrid control. This view displays data from the Orders.db table installed with the BDE.

First, key field values of selected records are stored in a list (FKeyFieldList) by the GetSelectedKeyValues procedure. To iterate selected records, the ForEachRow method is used. This enables you to call a custom procedure for each selected row (in this example, the AddKeyFieldValueToList procedure is called). The first parameter of ForEachRow specifies whether all or only selected rows should be processed.

Now every selected record is identified by a corresponding value in FKeyFieldList. For every selected record we need to create a query with an UPDATE command to will change the SaleDate field:

UPDATE Orders SET SaleDate = :SaleDate WHERE OrderNo = :OrderNo’

This updates the Orders table by setting a new value to the SaleDate field of the record(s) with the particular OrderNo value. The OrderNo and SaleDate field values are set via the query’s Params property.

After all the required records are changed, the dataset’s Refresh method is called in order to notify the data controller that data has changed and should be reloaded.

The main method, called to change selected records, is named Button1Click.

var
  FKeyFieldList: TList;
  FDataController: TcxDBDataController;
//...
procedure TForm1.Button1Click(Sender: TObject);
var
  AQuery: TQuery;
  I: Integer;
begin
  AQuery := TQuery.Create(Self);
  FKeyFieldList := TList.Create();
  try
    GetSelectedKeyValues(tvOrders.DataController);
    AQuery.ParamCheck := True;
    AQuery.DatabaseName := 'DBDEMOS';
    AQuery.SQL.Text := 'UPDATE Orders SET SaleDate = :SaleDate WHERE OrderNo = :OrderNo';
    //Set value for the SaleDate field
    AQuery.Params.ParamByName('SaleDate').Value := Now();
    //Iterate selected records
    for I := 0 to FKeyFieldList.Count - 1 do
    begin
      //Set value for the OrderNo field
      AQuery.Params.FindParam('OrderNo').Value := 
        Variant(Integer(FKeyFieldList[I]));
      //Execute the query
      AQuery.ExecSQL;
    end;
  finally
    FKeyFieldList.Free;
    AQuery.Free;
    tvOrders.DataController.DataSet.Refresh;
  end;
end;
procedure TForm1.GetSelectedKeyValues(ADataController: TcxDBDataController);
begin
  FDataController := ADataController;
  ADataController.ForEachRow(True, AddKeyFieldValueToList);
end;
procedure TForm1.AddKeyFieldValueToList(ARowIndex: Integer;
  ARowInfo: TcxRowInfo);
var
  AKeyFieldValue: Variant;
begin
  with FDataController do
  begin
    //test whether a row is a data record
    if ARowInfo.Level = Groups.GroupingItemCount then
    begin
      AKeyFieldValue := GetRecordId(ARowInfo.RecordIndex);
      FKeyFieldList.Add(Pointer(Integer(AKeyFieldValue)));
    end;
  end;
end;