【问题标题】:TFDMemTable lost/clearing data after filtering过滤后 TFDMemTable 丢失/清除数据
【发布时间】:2017-08-01 19:43:33
【问题描述】:

我创建了一个具有以下结构的 FDMemTable:

Cds_NaMenu := TFDMemTable.Create(nil);
Cds_NaMenu.FieldDefs.Add('ID', ftInteger);
Cds_NaMenu.FieldDefs.Add('MN_TELA_CODIGO', ftInteger);
Cds_NaMenu.FieldDefs.Add('MN_MENU_PESQUISA', ftString, 500);
Cds_NaMenu.FieldDefs.Add('DISPONIBILIDADE', ftInteger);
Cds_NaMenu.IndexDefs.Add('Ordem', 'MN_TELA_CODIGO', []);
Cds_NaMenu.CreateDataSet;
Cds_NaMenu.LogChanges := False;
Cds_NaMenu.IndexName := 'Ordem';

我把数据放在 TFDMemTable 中是这样的:

Cds_NaMenu.Append;
Cds_NaMenu.FieldByName('DISPONIBILIDADE').AsInteger := 1;
Cds_NaMenu.Post;

嗯...当将过滤属性设置为 True 并返回 False 时,就会出现问题。 RecordCount 属性变为 0;即使我使用 saveToFile 程序,也没有找到任何数据。显然数据丢失了。

_recCount := Cds_NaMenu.RecordCount; // Result = 867;
Cds_NaMenu.Filter := 'DISPONIBILIDADE=1 AND MN_MENU_PESQUISA like ' + QuotedStr('%' + sTexto + '%');
Cds_NaMenu.Filtered := True;
_recCount := Cds_NaMenu.RecordCount; // Result = 0;
Cds_NaMenu.Filtered := False;
Cds_NaMenu.Filter := '';
_recCount := Cds_NaMenu.RecordCount; // Result = 0;

PS:使用ClientDataSet,这段代码可以完美运行

【问题讨论】:

  • 依赖于数据集的 RecordCounts 返回有意义值的代码是在自找麻烦。除此之外,正如您所发现的,不同的数据集类型以不同的方式表现。听起来您的实际问题是 X/Y 问题。

标签: delphi filter firedac fdmemtable


【解决方案1】:

如果您使用的是纯内存表,则通过RecordCount 属性查询记录数应该没有问题。也许您希望在过滤 Value LIKE '%%' 时在过滤视图中包含 NULLempty 值记录,但事实并非如此。当有这样的数据集时:

ID | Value
1  | NULL
2  | ''
3  | 'Some text'

并像这样应用过滤器:

var
  S: string;
begin
  S := '';
  FDMemTable.Filtered := False;
  FDMemTable.Filter := 'Value LIKE ' + QuotedStr('%' + S + '%');
  FDMemTable.Filtered := True;
  { ← FDMemTable.RecordCount should be 1 here for the above dataset }
end;

视图中不应包含 emptyNULL 值记录。这是一个简短的证明:

var
  S: string;
  MemTable: TFDMemTable;
begin
  MemTable := TFDMemTable.Create(nil);
  try
    MemTable.FieldDefs.Add('ID', ftInteger);
    MemTable.FieldDefs.Add('Value', ftString, 500);
    MemTable.IndexDefs.Add('PK_ID', 'ID', [ixPrimary]);
    MemTable.CreateDataSet;

    MemTable.AppendRecord([1, NULL]);
    MemTable.AppendRecord([2, '']);
    MemTable.AppendRecord([3, 'Some text']);

    S := '';
    MemTable.Filtered := False;
    MemTable.Filter := 'Value LIKE ' + QuotedStr('%' + S + '%');

    ShowMessage(Format('Total count: %d', [MemTable.RecordCount])); { ← should be 3 }
    MemTable.Filtered := True;
    ShowMessage(Format('Filtered count: %d', [MemTable.RecordCount])); { ← should be 1 }
    MemTable.Filtered := False;
    ShowMessage(Format('Total count: %d', [MemTable.RecordCount])); { ← should be 3 }
  finally
    MemTable.Free;
  end;
end;

【讨论】:

  • 我完全同意你的看法!问题是: .RecordCount 在 Filtered 设置为 False 后不会回到 3。
【解决方案2】:

我认为这只是 FD 的一个小怪癖。下面的代码按预期工作,将 Cds_NaMenu 声明为 TFDMemTable(如果您可以删除 Cds_ 以避免混淆,那就太好了)。

我认为关键的区别在于过滤器被清除后对.Locate 的调用。我把它放在那里的原因是因为它导致数据集滚动,我想,结果是重新计算它的RecordCount。可能任何其他导致滚动的操作都会产生相同的效果,即使MoveBy(0) - 试试看。

procedure TForm1.FormCreate(Sender: TObject);
var
  _recCount : Integer;
  ID : Integer;
  sTexto : String;
begin
  sTexto := 'xxx';  // added

  Cds_NaMenu.FieldDefs.Add('ID', ftInteger);
  Cds_NaMenu.FieldDefs.Add('MN_TELA_CODIGO', ftInteger);
  Cds_NaMenu.FieldDefs.Add('MN_MENU_PESQUISA', ftString, 500);
  Cds_NaMenu.FieldDefs.Add('DISPONIBILIDADE', ftInteger);
  Cds_NaMenu.IndexDefs.Add('Ordem', 'MN_TELA_CODIGO', []);
  Cds_NaMenu.CreateDataSet;
  Cds_NaMenu.LogChanges := False;
  Cds_NaMenu.IndexName := 'Ordem';


  Cds_NaMenu.Append;
  Cds_NaMenu.FieldByName('ID').AsInteger := 666;  // added
  Cds_NaMenu.FieldByName('DISPONIBILIDADE').AsInteger := 1;
  Cds_NaMenu.Post;


  _recCount := Cds_NaMenu.RecordCount; // Result = 1

  ID := Cds_NaMenu.FieldByName('ID').AsInteger;  // added

  Cds_NaMenu.Filter := 'DISPONIBILIDADE=1 AND MN_MENU_PESQUISA like ' + QuotedStr('%' + sTexto + '%');
  Cds_NaMenu.Filtered := True;
  _recCount := Cds_NaMenu.RecordCount; // Result = 0;
  Cds_NaMenu.Filtered := False;
  Cds_NaMenu.Filter := '';

  // Now force the dataset to scroll
  if Cds_NaMenu.Locate('ID', ID, []) then;  // added
  _recCount := Cds_NaMenu.RecordCount; // Result = 1;
  Caption := IntToStr(_recCount);  // added
end;

【讨论】:

  • 如果是纯内存表的设置,则不需要“滚动获取”,因为一切都在客户端,不应该发生所描述的问题。
  • @Victoria,我当然意识到应该不需要滚动,但遇到过很多情况,不仅仅是 FireDAC,像这样的问题可以通过强制滚动来解决,甚至如果它什么都不做,比如MoveBy(0)。顺便说一句,如果我去帮助 | 我猜对了吗? Alt-Team 是否会欺骗不热衷于 Firebird 的人的名字滚动到视图中;=)?
  • 刚刚应用了过滤器,并且不得不强制滚动,难道不更容易阅读并且只需调用 First 就足够了吗?
  • @Frazz: 更简单,为什么?我使用了Locate,因为这意味着用户不会失去他在数据集中的位置。
  • @维多利亚。听起来你的猜测不错,我已经 +1 了你的答案。
猜你喜欢
  • 2015-10-25
  • 2015-03-11
  • 2012-03-14
  • 2017-12-30
  • 2014-02-03
  • 1970-01-01
  • 2021-07-27
  • 2013-08-05
  • 1970-01-01
相关资源
最近更新 更多