簡體   English   中英

如何在內部處理過濾后的tDataSet記錄,不要在tDBGrid上顯示結果

[英]How to internally process filtered tDataSet records not to be shown on tDBGrid the result

在下面的tFDMemTable中,我嘗試對ID字段以字母A開頭的記錄的值進行求和.A1,A2和結果應為4。

type
  TForm1 = class(TForm)
    FDMemTable1: TFDMemTable;
    DBGrid1: TDBGrid;
    DataSource1: TDataSource;
    Button1: TButton;
    Button2: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  end;

procedure TForm1.FormCreate(Sender: TObject);
var
  _FieldDef: TFieldDef;
begin
  _FieldDef := FDMemTable1.FieldDefs.AddFieldDef;

  _FieldDef.Name := 'ID';
  _FieldDef.DataType := ftString;
  _FieldDef.Size := 5;

  _FieldDef := FDMemTable1.FieldDefs.AddFieldDef;

  _FieldDef.Name :='value';
  _FieldDef.DataType := ftInteger;

  FDMemTable1.CreateDataSet;

  FDMemTable1.Append;

  FDMemTable1.FieldValues['ID'] := 'A1';
  FDMemTable1.FieldValues['value'] := 1;

  FDMemTable1.Append;

  FDMemTable1.FieldValues['ID'] := 'B1';
  FDMemTable1.FieldValues['value'] := 2;

  FDMemTable1.Append;

  FDMemTable1.FieldValues['ID'] := 'A2';
  FDMemTable1.FieldValues['value'] := 3;

  FDMemTable1.Append;

  FDMemTable1.FieldValues['ID'] := 'B2';
  FDMemTable1.FieldValues['value'] := 4;
end;

我編寫了以下代碼,但它將tDBGrid更改為已過濾。 我想要的只是一個內部過程,tDBGrid應該保持不變。

procedure TForm1.Button1Click(Sender: TObject);
var
  _ValueSum: Integer;
  i: Integer;
begin
  FDMemTable1.Filter := 'ID like ' + QuotedStr('A%');

  FDMemTable1.Filtered := True;

  _ValueSum := 0;

  FDMemTable1.FindFirst;

  for i := 0 to FDMemTable1.RecordCount - 1 do
  begin
    _ValueSum := _ValueSum + FDMemTable1.FieldValues['value'];

    FDMemTable1.FindNext;
  end;

  Button1.Caption := IntToStr(_ValueSum);
end;

我知道tDataSet.Locate不允許NEXT SEARCH,我嘗試了這樣的原始方式。 它工作正常,但似乎有點愚蠢。

procedure TForm1.Button2Click(Sender: TObject);
var
  _ValueSum: Integer;
  i: Integer;
begin
  _ValueSum := 0;

  FDMemTable1.First;

  for i := 0 to FDMemTable1.RecordCount do
  begin
    if Copy(FDMemTable1.FieldValues['ID'], 1, 1) = 'A' then
    begin
      _ValueSum := _ValueSum + FDMemTable1.FieldValues['value'];
    end;

    FDMemTable1.FindNext;
  end;

  Button2.Caption := IntToStr(_ValueSum);
end;

當我在過濾之前斷開tFDMemTable和tDBGrid或設置非活動以保持最后一個網格狀態時,網格將變為空白狀態。 最后一個代碼是最好的解決方案還是有更好的方法,在過濾工作時顯示未過濾的結果?

有幾件事,如果不是“錯誤的”,對你的代碼來說是不對的。

  1. 您應該使用Next而不是FindNext移動到數據集中的下一行。 Next移動到數據集中的下一行,而FindNext移動到下一行,該行匹配您已經設置的搜索條件,例如使用DataSet.SetKey; ... DataSet.SetKey; ... - 閱讀FindKey用法的在線幫助。

  2. 您不應該嘗試使用For循環遍歷數據集; 使用While not FDMemData.Eof do循環。 Eof代表“文件結束”,一旦數據集位於其最后一行,則返回true。

  3. 你應該調用FDMemTable1.DisableControls循環之前和FDMemTable1.EnableControls之后。 這可以防止像DBGrid這樣的db-aware控件在循環內更新,否則會在網格更新時減慢循環速度。

  4. 除非你有充分的理由不這樣做,否則總是按照你設置的方法清除數據集過濾器,否則如果忘記過濾器處於活動狀態,你可能會遇到一些非常令人困惑的錯誤。

  5. 當你不是絕對需要時盡量避免使用RecordCount 根據您使用的RDMS,它可能會在服務器和網絡上產生大量可避免的處理開銷(因為某些服務器類型會導致整個數據集被檢索到客戶端)。

將您的第一個循環更改為

procedure TForm1.Button1Click(Sender: TObject);
var
  _ValueSum : Integer;
begin
  _ValueSum := 0;

  FDMemTable1.Filter := 'ID like ' + QuotedStr('A%');

  try
    FDMemTable1.DisableControls;
    FDMemTable1.First;
    while not FDMemTable1.Eof do begin
      _ValueSum:= _ValueSum + FDMemTable1.FieldByName('Value').AsInteger;
      FDMemTable1.Next;
    end
  finally
    FDMemTable1.Filter := '';
    FDMemTable1.Filtered := False;
    FDMemTable1.EnableControls;
  end;
   Button1.Caption := IntToStr(_ValueSum);
end;

如果你這樣做,根本不需要你的Button2Click方法。

如評論中所述,您可以使用TBookMark在循環之前在數據集中記錄您的位置,然后返回到它,如

var
  _ValueSum : Integer;
  BM : TBookMark;
begin
  _ValueSum := 0;

  BM := FDMemTable.GetBookMark;

  FDMemTable1.Filter := 'ID like ' + QuotedStr('A%');

  try
    [etc]
  finally
    FDMemTable1.Filter := '';
    FDMemTable1.Filtered := False;
    FDMemTable1.GotoBookMark(BM);
    FDMemTable1.FeeBookMark(BM);
    FDMemTable1.EnableControls;
  end;

順便說一句,您可以使用InsertRecord方法保存自己的一些輸入並獲得更簡潔的代碼

FDMemTable1.InsertRecord(['A1', 1]);
FDMemTable1.InsertRecord(['B1', 2]);
FDMemTable1.InsertRecord(['A2', 3]);
FDMemTable1.InsertRecord(['B2', 4]);

順便說一下#2:使用FindKey的時間是在你設置了一個要查找的密鑰之后,通過調用SetKey不是設置密鑰值。

對於數據集的普通導航,請使用標准導航方法,例如NextPriorFirstLastMoveBy等。

FireDAC還有另一個有趣的選擇 - 聚合:

procedure TForm1.Button1Click(Sender: TObject);
begin
  FDMemTable1.Aggregates.Clear;
  with FDMemTable1.Aggregates.Add do
  begin
    Name := 'SUM';
    Expression := 'sum(iif(ID like ''A%'', value, 0))';
    Active := True;
  end;
  FDMemTable1.AggregatesActive := True;
  FDMemTable1.Refresh;
  Button1.Caption := VarToStr(FDMemTable1.Aggregates[0].Value));
end;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM