TDataset.Locate 在所有领域

TDataset.Locate in all field

假设我们有一个包含 5 个字段的数据集,显示在 DBGrid 中。

用户想要在网格中的任意位置定位文本。

如果我想搜索所有字段或者我必须实现自定义代码来实现此目的,有什么方法可以使用 TDataset.Locate() 方法吗?

简短的回答是您需要一些自定义代码,因为当您使用多个字段调用 Locate 时,您必须传递一个变体数组,其中包含您要在相应字段中匹配的值。虽然您可以指定匹配可以基于部分键(字段)值,但要匹配的模式不能跨越多个字段。

幸运的是,有一个简单的方法可以达到你想要的结果,如下所示:

  1. 将FieldKind fkInternalCalc的计算字符串字段添加到数据集,我们称之为AllFields。

  2. 在数据集的 OnCalcFields 中,将 AllField 的值设置为数据集所有其他字段的 AsString 值的串联;

  3. 针对 AllFields 字段调用 Locate,代码如下

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

这就是你所需要的。

例子

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;

注意:要使上述代码正常工作,MyDataSet 的数据集类型必须是 支持 fkInternalCalc 字段类型,例如 TClientDataSet。