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

问题描述 投票:3回答:2

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

1 10 100 101 11 110 111 12 120

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

1 10 11 12 100 101 110 111 120

有快速的方法吗?

delphi delphi-7
2个回答
8
投票

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

设置计算字段的find tp fkInternalCalc的点是CDS可以在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-Tree索引的密钥更窄,以及Delphi中针对先前长字符串对象的堆内存分配减少。
  • 关注字符串和字符串比较的细微差别。例如。意想不到的填充。
  • 强大的打字保证你不会出乎意料地处理'有问题的字符串'。您提出了一个问题,即您是否会因为进行更改而“产生任何负面后果”。我不知道。但是,不进行更改确实会产生意外非整数项目编号的后果。

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

'03', '13', '3', 'B2', '  13 ', '3bad'

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

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

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


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

© www.soinside.com 2019 - 2024. All rights reserved.