TClientDataset:有没有办法让 StringField 在设置索引时表现得像 IntegerField?

TClientDataset: Is there a way to make a StringField behave like an IntegerField when setting an index?

我想按包含整数的 StringFieldClientDataset 进行排序。这些整数用作发票上的项目编号。当我使用简单索引按该字段对 ClientDataset 进行排序时,结果是这样的:

1
10
100
101
11
110
111
12
120

但是我希望它们像 IntegerField:

一样排序

1
10
11
12
100
101
110
111
120

有快速的方法吗?

您无需将现有字段更改为其他类型。相反,做你想做的事情的一种方法是在 FieldFind fkInternalCalc 的 CDS 上定义一个 ftInteger 字段。然后在 CDS 的 OnCalcFields 事件中,通过将字符串字段的值转换为整数来设置字段的值。

设置计算字段的 find tp fkInternalCalc 的要点是 CDS 可以在 fkInternalCalc 字段上建立索引,因此可以按 fkInternalCalc 字段排序,这与 fkCalculated 字段不同。因此,通过在添加的 fkInternalCalc 字段上为您的 CDS 编制索引,记录应该按数字顺序显示,而不是按字符串字段的字母数字顺序显示。

代码:

procedure TForm1.CDS1CalcFields(DataSet: TDataSet);
begin
  if CDS1IntField.IsNull then
    CDS1IntField.AsInteger := StrToInt(CDS1StringField.AsString);
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  i : Integer;
begin
  CDS1.CreateDataSet;
  for i := 1 to 100 do
    CDS1.InsertRecord([IntToStr(i)]);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  CDS1.IndexFieldNames := 'IntField';
end;

如果您想按整数排序:到目前为止,最好的方法是:将类型更改为整数。

是的,工作量更大,但是听我说完


目前您有 2 种可能性:要么您所有的值当前都是 规范1 整数,要么不是。

如果是,那么您确实有一些工作要做。您需要更改:

  • 数据库中的列
  • 任何包含相同数据的外键列
  • 这些列的任何持久化字段的类型
  • 任何需要字符串项目编号的代码

并且您将获得以下好处:

  • 更好的性能归因于:单操作比较、内存中的数据更少、B 树索引的键更窄以及 Delphi 中先前长字符串对象的堆内存分配减少。
  • 较少关注字符串和字符串比较的细微差别。例如。意外填充。
  • 并且强类型保证您不会意外地不得不处理 'problematic strings'。您担心是否会 "have any negative consequences" 由于进行更改。我什么都不知道。 但是,不进行更改冒意外的非整数项目编号的后果。

但是,如果您的商品编号不是规范的整数:那么尝试按整数排序已经有问题了。您如何将以下项目编号排序为整数?

'03', '13', '3', 'B2', '  13 ', '3bad'
在这种情况下,

是最好的方法。因为您保留了原始字符串值,所以您仍然拥有一个安全可靠的密钥。 (注意仅使用内部计算字段进行排序)。

请注意,您必须调整:CDS1IntField.AsInteger := StrToInt(CDS1StringField.AsString); 行以确保您可以设置合理的排序值。由于无法转换某些字符串而引发的任何异常都会导致严重的问题。

作为奖励,在您调查较大变化的连锁反应之前,Martyn 的答案在短期内是安全的。但您可能想为 'big job'.

安排时间

1 关于“规范”整数的观点很微妙但很重要。在整数前加上任意数量的零或空格会产生 非规范 重复项。考虑“3”和“03”。作为整数它们是相同的,但作为字符串它们是不同的。