TJvCsvDataSet 和过滤器

TJvCsvDataSet and filter

我在过滤上传到 TJvCsvDataSet 中的 .csv 文件时遇到问题。 下面是MCVE的解释

program Project3;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  JvCsvData,
  data.DB;

var
  FJvCsvDataSet: TJvCsvDataSet;
I:Integer;
begin
  ;
  FJvCsvDataSet := TJvCsvDataSet.Create(nil);
  FJvCsvDataSet.CsvFieldDef :=
    'VTHB:%,VTHS:%,VTHBBP:&,VTBBSP:&,VTHBLP:&,VTHBLS:&,VTHTS:@';
  FJvCsvDataSet.FieldDefs.Add('VTHB', ftInteger, 0, False);
  FJvCsvDataSet.FieldDefs.Add('VTHS', ftInteger, 0, False);
  FJvCsvDataSet.FieldDefs.Add('VTHBBP', ftFloat, 0, False);
  FJvCsvDataSet.FieldDefs.Add('VTBBSP', ftFloat, 0, False);
  FJvCsvDataSet.FieldDefs.Add('VTHBLP', ftFloat, 0, False);
  FJvCsvDataSet.FieldDefs.Add('VTHBLS', ftFloat, 0, False);
  FJvCsvDataSet.FieldDefs.Add('VTHTS', ftDateTime, 0, False);

    FJvCsvDataSet.FileName :=
    'E:\...\abc.csv';
  FJvCsvDataSet.Open;
  FJvCsvDataSet.First;
//  FJvCsvDataSet.Sort('VTHB,VTHBBP', True);
  FJvCsvDataSet.Filtered := False;
  FJvCsvDataSet.Filter := '';
  for I := 1 to 1093 do
  begin
    FJvCsvDataSet.Filter:='VTHB=' + IntToStr(I);
    FJvCsvDataSet.Filtered := True;
  end;
  FJvCsvDataSet.Free;
end.

下面是FJvCsvDataSet

上传的abc.csv样本
VTHB,VTHS,VTHBBP,VTBBSP,VTHBLP,VTHBLS,VTHTS
1,1,3.05,279.86,3.1,115.98,2019-08-10 14:28:47.505
1,2,3.9,259.65,3.95,237.73,2019-08-10 14:28:47.52
1,3,3.9,136.48,3.95,31.97,2019-08-10 14:28:47.52
1,5,10.5,68.83,11,52.03,2019-08-10 14:28:47.52
1,4,12.5,41.4,13,47.75,2019-08-10 14:28:47.52
2,1,3.05,279.86,3.1,115.98,2019-08-10 14:28:47.863
2,2,3.9,259.65,3.95,237.73,2019-08-10 14:28:47.863
2,3,3.9,136.48,3.95,31.97,2019-08-10 14:28:47.863
2,5,10.5,68.83,11,52.03,2019-08-10 14:28:47.863
2,4,12.5,41.4,13,47.75,2019-08-10 14:28:47.863

当执行语句FJvCsvDataSet.Filter:='VTHB=' + IntToStr(I);FJvCsvDataSet.RecordCount没有改变因此不执行过滤

我做错了什么?

我不认为你在做什么"wrong",似乎 TJvCsvDataSet 以一种相当奇怪的方式实现过滤。

使用您的代码设置和打开数据集,以下代码工作正常并生成预期的记录(在您代码的 VCL 版本的 DBGrid 中观察到):

FJvCsvDataSet.SetFilterNum('VTHB', jfIntEqual, 1);
FJvCsvDataSet.Filtered := True;

这会导致 FJvCsvDataSet.RecordCount 为 5,这是应该的。这种过滤方式使用以下枚举作为 SetFilterNum 的第二个参数:

TJvCsvFilterNumCompare = (jfIntEqual, jfIntNotEqual, jfLessThan, jfGreaterThan);

但是,改为这样做

FJvCsvDataSet.Filter:= 'VTHB=1';

产生不正确的结果,即没有记录被过滤掉并且 RecordCount 为 10。显然出了问题,我稍后会回来告诉我是否找到它是什么。

更新 我进一步研究了一下,确实有些东西 奇怪的事情发生了。

正在做

FJvCsvDataSet.Filter:= 'VTHB = 1';
FJvCsvDataSet.Filtered := True;

没有任何影响,数据集甚至不扫描记录以查看它们是否 匹配过滤器。 OTOH 这样做

FJvCsvDataSet.SetFilter('VTHB', '1');
FJvCsvDataSet.Filtered := True;

会导致行开始扫描,通过 SetFilter 方法

// string Filtering: Make Rows Visible Only if they match filterString
procedure TJvCustomCsvDataSet.SetFilter(const FieldName: string; Pattern: string);

并且这些行是否正确标记为已过滤取决于它们是否与过滤器匹配。 然而,至少有两件奇怪的事:

  • 所有的记录,无论匹配与否,仍然以网格显示。我认为这 意味着问题出在其他地方,可能与 InternalSkipFiltered 方法有关, 但是 FJvCsvDataSet.SetFilterNum('VTHB', jfIntEqual, 1) 怎么会起作用呢? 需要进一步探索。

  • 应用过滤器后在数据集上调用关闭和打开不会导致 正在重新扫描的行,从逻辑上讲应该如此,但是我们不调用 SetFilter 第二次,所以这大概是 WAD。但这是一个奇怪的设计,因为 SeFilter 首先不应该公开访问,它应该由 setter 为 Filter 属性 调用,imo.

更新 #2 好吧,我们不能说我们没有收到警告

https://wiki.delphi-jedi.org/wiki/JVCL_Help:TJvCustomCsvDataSet.SetFilter

Note that this feature is NOT API-compatible with or similar to the filtering feature that is normally found in VCL TTable component.

前面的描述是根据将字段过滤为字符数据来表达的,所以我想知道它是否曾经打算处理 ftInteger 字段....