简体   繁体   English

如果还有日期时间字段,Delphi 10.4 无法在 DBGrids 上显示十进制 (5,2) BCD 字段

[英]Delphi 10.4 fails to show decimal(5,2) BCD fields on DBGrids if there also is a datetime field

When I have a ClientDataset with datetime fields and decimal(5,2) fields, Delphi 10.4 can't show them on a TDBGrid, it raises a convert exception.当我有一个带有日期时间字段和十进制(5,2)字段的 ClientDataset 时,Delphi 10.4 无法在 TDBGrid 上显示它们,它会引发转换异常。

I have prepared an small test project to show this error (my real data comes from SQL Server, although I can get the same error filling the Clientdataset manually).我准备了一个小测试项目来显示这个错误(我的真实数据来自 SQL 服务器,虽然我可以手动填充 Clientdataset 得到相同的错误)。

procedure TForm1.FormCreate(Sender: TObject);
var ClientDataset: TClientDataset;
    Datasource: TDatasource;
    DBGrid: TDBGrid;
begin
  ClientDataset := TClientDataset.Create(Self);
  ClientDataset.FieldDefs.Add('Id', ftInteger);
  ClientDataset.FieldDefs.Add('Date', ftDateTime);
  ClientDataset.FieldDefs.Add('Decimal', ftBCD, 2);
  ClientDataset.FieldDefs.Find('Decimal').Precision := 5;
  ClientDataset.CreateDataSet;
  Datasource := TDatasource.Create(Self);
  Datasource.Dataset := ClientDataset;

  ClientDataset.Insert;
  ClientDataset.FieldValues['id'] := 1;
  ClientDataset.FieldValues['Date'] := Now;
  ClientDataset.FieldValues['Decimal'] := 7.55;
  ClientDataset.Post;
  ClientDataset.Insert;
  ClientDataset.FieldValues['id'] := 2;
  ClientDataset.FieldValues['Date'] := Now;
  ClientDataset.FieldValues['Decimal'] := 8.2;
  ClientDataset.Post;

  DBGrid := TDBGrid.Create(Self);
  DBGrid.Parent := Self;
  DBGrid.Align := alClient;
  DBGrid.Datasource := Datasource;
end;

It raises this exception: '8200@' is not a valid integer value它引发了这个异常: '8200@' is not a valid integer value

A decimal(18,2) doesn't have this problem, if I comment the line ClientDataset.FieldDefs.Find('Decimal').Precision:= 5;如果我注释ClientDataset.FieldDefs.Find('Decimal').Precision:= 5;行,小数(18,2)就没有这个问题then no error is raised.然后不会引发错误。

Also, if there is no datetime field then no error is raised either.此外,如果没有日期时间字段,则也不会引发错误。 This runs fine:这运行良好:

procedure TForm1.FormCreate(Sender: TObject);
var ClientDataset: TClientDataset;
    Datasource: TDatasource;
    DBGrid: TDBGrid;
begin
  ClientDataset := TClientDataset.Create(Self);
  ClientDataset.FieldDefs.Add('Id', ftInteger);
  ClientDataset.FieldDefs.Add('Decimal', ftBCD, 2);
  ClientDataset.FieldDefs.Find('Decimal').Precision := 5;
  ClientDataset.CreateDataSet;
  Datasource := TDatasource.Create(Self);
  Datasource.Dataset := ClientDataset;

  ClientDataset.Insert;
  ClientDataset.FieldValues['id'] := 1;
  ClientDataset.FieldValues['Decimal'] := 7.55;
  ClientDataset.Post;
  ClientDataset.Insert;
  ClientDataset.FieldValues['id'] := 2;
  ClientDataset.FieldValues['Decimal'] := 8.2;
  ClientDataset.Post;

  DBGrid := TDBGrid.Create(Self);
  DBGrid.Parent := Self;
  DBGrid.Align := alClient;
  DBGrid.Datasource := Datasource;
end;

Do you think that this could be fixed without having to replace all my decimal(5,2) fields with decimal(18,2) fields?.您是否认为无需将所有小数(5,2)字段替换为小数(18,2)字段即可解决此问题?

UPDATE: This is a problem specific of the ClientDataset.更新:这是特定于 ClientDataset 的问题。 If I open the same data on a TADOQuery or TFDMemTable (with the exact same datetime and decimal(5,2) BCD fields), Delphi 10.4 shows the DBGrid without any issue.如果我在 TADOQuery 或 TFDMemTable 上打开相同的数据(具有完全相同的 datetime 和 decimal(5,2) BCD 字段),Delphi 10.4 显示 DBGrid 没有任何问题。

The problem is also specific of the DBGrid.该问题也特定于 DBGrid。 There is no problem displaying those fields on DBEdits.在 DBEdits 上显示这些字段没有问题。

Changes have been made in version 10.4 on the unit Data.FmtBcd about functions BCDToCurr e BCDToCurrency.版本 10.4 中已对单元 Data.FmtBcd 关于函数 BCDToCurr e BCDToCurrency 进行了更改。

Delphi 10.3 Delphi 10.3

function BCDToCurr(const BCD: TBcd; var Curr: Currency): Boolean;
  Curr := StrToCurr(string(Bcd));
  Result := True;
end;

function BCDToCurrency(const BCD: TBcd): Currency;
begin
  Result := StrToCurr(string(Bcd)); 
end;

Delphi 10.4 Delphi 10.4

function BCDToCurr(const BCD: TBcd; var Curr: Currency): Boolean;
var
  B: TBcd;
  S: string;
const
  DecimalSeparator = '.';
begin
  // B := BCD * 10000;
  B := BCD;
  if BcdScale(B) >= 4 then
    Dec(B.SignSpecialPlaces, 4)
  else if BcdPrecision(B) <= (MaxFMTBcdFractionSize - 4) then
    Inc(B.Precision, 4)
  else
    OverflowError(SBcdOverflow);

  S := BcdToStr(B, DecimalSeparator);
  Round(S, DecimalSeparator, 0);
  // The real format of Currency type is Int64.
  PInt64(@Curr)^ := StrToInt64(S);
  Result := True;
end;

function BCDToCurrency(const BCD: TBcd): Currency;
begin
  BCDToCurr(BCD, Result);
end;

So, with precision:=5 in BCDToCurr function:因此,精度:= 5 in BCDToCurr function:

else if BcdPrecision(B) <= (MaxFMTBcdFractionSize - 4) then Inc(B.Precision, 4)否则,如果 BcdPrecision(B) <= (MaxFMTBcdFractionSize - 4) 那么 Inc(B.Precision, 4)

and B.Precision increment to 9. The variable Curr then takes an incorrect value. B.Precision 增量为 9。然后变量 Curr 采用不正确的值。

I reported the bug and now has been fixed in the recent Delphi 10.4 Update 1.我报告了这个错误,现在已经在最近的 Delphi 10.4 Update 1 中修复。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM