TClientDataset:有没有办法在设置索引时使StringField像IntegerField一样?

时间:2018-01-02 12:16:21

标签: delphi delphi-7

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

1
10个
100个
101个
11个
110个
111个
12个
120

但是我希望它们像 IntegerField 那样排序:

1
10个
11个
12个
100个
101个
110个
111个
120

有快速的方法吗?

2 个答案:

答案 0 :(得分:8)

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

设置计算字段的find tp fkInternalCalc的意思是,与fkCalculated字段不同,CDS可以在fkInternalCalc字段上编入索引,因此可以按fkInternalCalc字段排序。因此,通过在添加的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;

答案 1 :(得分:2)

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

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

目前,您有两种可能性:要么所有值都是规范 1 整数,要么它们不是。

如果是,那么你确实需要做一些工作。你需要改变:

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

您将获得以下好处:

  • 由于以下方面的更好性能:单个操作比较,内存中的数据更少,B-Tree索引的键更窄,以及Delphi中针对先前长字符串对象的堆内存分配减少。
  • 不太关心字符串的细微差别和字符串比较。例如。意想不到的填充。
  • 强大的打字保证您不会出乎意料地处理有问题的字符串'。你提出了一个问题,即你是否会产生任何负面影响"由于做出改变。我不知道。 但是,不进行更改确实会冒着意外的非整数商品编号的后果。

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

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

Martyn's answer将是最佳方式。因为您保留了原始字符串值,所以您仍然拥有安全可靠的密钥。 (NB仅使用内部计算字段进行排序)。

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

作为奖励,在您调查较大变化的连锁效应之前,Martyn的答案在短期内是安全的。但是,您可能希望为“大工作”安排时间。

1 关于' 规范'整数是微妙但重要的。将任意数量的零或空格前缀为整数会产生非规范重复。考虑" 3"和" 03"。作为整数,它们是相同的,但作为字符串,它们是不同的。