Home > Software engineering >  TDataset.Locate in all field
TDataset.Locate in all field

Time:09-28

Lets say we have a Dataset with 5 fields, displayed in a DBGrid.

User want to locate a text, anywhere in the grid.

Is there any way to use TDataset.Locate() method if I want to search thru all the fields or I have to implement a custom code to achieve this?

CodePudding user response:

The short answer is that you will need some custom code, because when you call Locate with more than one field, you have to pass a variant array containing the value you want to match in the corresponding field. Although you can specify that the match can be based on partial key (field) values, the pattern to match cannot span more than one field.

Fortunately there is a straightforward way to achieve the result you want, which is as follows:

  1. Add a calculated string field of FieldKind fkInternalCalc to the dataset, let's call it AllFields.

  2. In the dataset's OnCalcFields set AllField's value to the concatenation of the AsString values of all the other fields of the dataset;

  3. Call Locate against the AllFields field, with code like

    if MyDataSet.Locate('AllFields', AValue, [loPartialKey]) then;

That's all you need.

Example

type
  TForm1 = class(TForm)
    DBGrid1: TDBGrid;
    MyDataSet: TClientDataSet;
    DataSource1: TDataSource;
    Button1: TButton;
    DBNavigator1: TDBNavigator;
    edSearch: TEdit;
    procedure FormCreate(Sender: TObject);
    procedure MyDataSetCalcFields(DataSet: TDataSet);
    procedure edSearchChange(Sender: TObject);
  end;

[...]

procedure TForm1.FormCreate(Sender: TObject);
var
  AField : TField;
  i : Integer;
begin
  AField := TIntegerField.Create(Self);
  AField.FieldName := 'ID';
  AField.DataSet := MyDataSet;

  AField := TStringField.Create(Self);
  AField.FieldName := 'FieldA';
  AField.DataSet := MyDataSet;

  AField := TStringField.Create(Self);
  AField.FieldName := 'FieldB';
  AField.DataSet := MyDataSet;

  AField := TStringField.Create(Self);
  AField.FieldName := 'FieldC';
  AField.DataSet := MyDataSet;

  AField := TStringField.Create(Self);
  AField.FieldName := 'FieldD';
  AField.DataSet := MyDataSet;

  AField := TStringField.Create(Self);
  AField.FieldName := 'AllFields';
  AField.Size := 255;  //  increase if necessary
  AField.FieldKind := fkInternalCalc;  //  not fkCalculated
  AField.DataSet := MyDataSet;

  MyDataSet.CreateDataSet;

  for i := 1 to 100 do begin
    MyDataSet.InsertRecord([i, 'value'  IntToStr(i), 'value'  IntToStr(i), 'value'  IntToStr(i), 'value'  IntToStr(i)]);
  end;
end;

procedure TForm1.MyDataSetCalcFields(DataSet: TDataSet);
var
  S : String;
  i : Integer;
begin
  S := '';
  for i := 0 to DataSet.FieldCount - 2 do  //  the 2 is to stop the loop before the AllFields filed
    S := S   DataSet.Fields[i].AsString;

  DataSet.Fields[5].AsString := S; //  AllField is field 5
end;

procedure TForm1.edSearchChange(Sender: TObject);
begin
  if edSearch.Text <>'' then
    MyDataSet.Locate('AllFields', edSearch.Text, [loPartialKey, loCaseInsensitive])
  else
    MyDataSet.First;
end;

Note: for the above code to work, MyDataSet's dataset type needs to be one which supports the fkInternalCalc field kind, such as TClientDataSet.

  • Related