【问题标题】:ClientDataSet rounds number to 15 digitsClientDataSet 将数字四舍五入为 15 位
【发布时间】:2012-08-17 15:45:45
【问题描述】:

我有一个 Delphi XE 应用程序,它使用 TClientDataSetTDataSetProvider 以及后面的 TADOQuery 访问 Oracle XE 数据库。 我要写入的表有一个NUMBER(19) 字段。

我正在向其中写入一个值,如下所示:

myDataModule.myClientDataSet.FieldByName('ID').AsLargeInt := ID;

假设我有一个像 1234567890123456789 这样的 ID,它会四舍五入为 1234567890123460000

我怎样才能避免这种情况?

【问题讨论】:

  • 你能检查一下 myDataModule.myClientDataSet.FieldByName('ID').DataType 吗?
  • 这给了我“不可用的值”,尽管单步执行 DB.pas 代码表明它被错误地识别为 TFloatField。为作业显式转换字段无济于事。所以我需要找出如何像 Arnaud 所说的那样强制创建 ftLargeint。
  • 尝试将TADOQuery.EnableBCD设置为True。
  • 这样做会返回一个 EVariantOverflowError "'在将类型(十进制)的变体转换为类型(货币)时溢出。"
  • 那就考虑迁移到3d方Delphi Oracle数据访问组件。

标签: database delphi ado


【解决方案1】:

确保您的TClientDataSet 字段明确创建为ftLargeint,否则您可能会遇到此类舍入问题。

忘记使用 ADO 访问 Oracle。请注意,由 ADO 连接的所有 OleDB 提供程序在处理 BLOB 时都存在错误:Microsoft 的版本只是不处理它们,而 Oracle 的版本将 randomly return null for 1/4 of rows... 如果在您的案例中出现类似的问题,关于数字字段,我不会感到惊讶。

您可以查看访问 Oracle 的其他方法,例如 DBExpresss 驱动程序甚至 BDE。一些第三方组件也可用。

我们的免费 direct access classes to Oracle 可以原生处理此类数字字段,并将直接处理 Int64 值,无需 TDataSet 转换(这也可能是问题的原因)。例如,我认为它是唯一实现名为“64-bit Integer Host Datatype for OCI Bind and Define calls”的最新 11g 功能的 Delphi 单元。它不需要客户端驱动程序(也不需要 BDE、Provider 或本地配置):您只需使用 Delphi exe 复制 Oracle Instance Client dll 即可直接连接到 Oracle。结果speed is amazing

【讨论】:

  • 首先我尝试使用 DBExpress 组件来访问 Oracle。这些在 Delphi 7 中运行良好。虽然在 Delphi XE 中它们造成了很大的麻烦。不幸的是,我不能再告诉,究竟是因为那是半年前的问题。从那以后,我搬到了 ADO,它一直工作到现在。
  • ADO/OleDB 如果您不使用 BLOB,并且您的问题没有遇到路由问题,则可以正常工作! ;)
  • 我之前已经听说过 BLOB 问题。我没有在我的表中使用任何 BLOB,所以幸运的是我对此没有任何问题。虽然我仍然不知道如何告诉TClientDataSet 使用我现在为它定义的FieldDefs
【解决方案2】:

您是否在您的 Delphi 项目选项中设置了use debug .dcus,并逐步执行了从初始变量分配到将数据传递给 Oracle 传输驱动程序的所有代码?您是否验证了该值何时四舍五入到 15 位?

以下是其他论坛中的一些帖子,非 Delphi 用户遇到了同样的问题,这是由使用 to_char() 函数引起的。我想知道number(19)(或BigInt)值是否在您设置值和发布到数据库之间的某个位置被转换为字符串。

【讨论】:

    【解决方案3】:

    我决定扔掉TClientDataSetTDataSetProvider,直接使用TADOQuery插入值。

    即我现在有这样的东西:

    myDataModule.myQuery.SQL.Clear;
    myDataModule.myQuery.SQL.Add('INSERT INTO mytable (ID) VALUES(:ID)');
    myDataModule.myQuery.Prepared := True;
    myDataModule.myQuery.Parameters.ParamByName('ID').Value := 1234567890123456789;
    myDataModule.myQuery.ExecSQL;
    

    不是一个完美的解决方案,但它有效。

    【讨论】:

      猜你喜欢
      • 2014-08-26
      • 1970-01-01
      • 1970-01-01
      • 2015-11-12
      • 2014-08-26
      • 2023-03-24
      • 2012-09-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多