【问题标题】:DataAdapter.Fill() throws overflow exception on loading large decimal valuesDataAdapter.Fill() 在加载大十进制值时抛出溢出异常
【发布时间】:2019-01-14 14:10:25
【问题描述】:

我正在尝试从导致异常的 MySQL 和 Oracle 数据库加载大的十进制值。我知道当它试图将值转换为 .Net 的十进制数据类型时会导致异常,但是从数据库中读取如此巨大的值的方法是什么?

来自 MySQL 数据库的异常

System.Number.ParseDecimal(字符串值,NumberStyles 选项, NumberFormatInfo numfmt) 在 System.Convert.ToDecimal(String value, IFormatProvider 提供程序)在 MySql.Data.Types.MySqlDecimal.MySql.Data.Types.IMySqlValue.get_Value() 在 MySql.Data.MySqlClient.MySqlDataReader.GetValue(Int32 i) 在 MySql.Data.MySqlClient.MySqlDataReader.GetValues(Object[] values) 在 System.Data.ProviderBase.SchemaMapping.LoadDataRow() 在 System.Data.Common.DataAdapter.FillLoadDataRow(SchemaMapping 映射) 在 System.Data.Common.DataAdapter.FillFromReader(DataSet 数据集, DataTable datatable, String srcTable, DataReaderContainer dataReader, Int32 startRecord, Int32 maxRecords, DataColumn parentChapterColumn, 对象 parentChapterValue) 在 System.Data.Common.DataAdapter.Fill(DataTable[] 数据表, IDataReader dataReader, Int32 startRecord, Int32 maxRecords) 在 System.Data.Common.DbDataAdapter.FillInternal(数据集数据集, DataTable[] 数据表,Int32 startRecord,Int32 maxRecords,字符串 srcTable、IDbCommand 命令、CommandBehavior 行为)在 System.Data.Common.DbDataAdapter.Fill(DataTable[] 数据表,Int32 startRecord、Int32 maxRecords、IDbCommand 命令、CommandBehavior 行为)在 System.Data.Common.DbDataAdapter.Fill(DataTable 数据表)

来自 Oracle 数据库的异常

System.OverflowException:算术运算导致 溢出。在 Oracle.DataAccess.Types.DecimalConv.GetDecimal(IntPtr numCtx) 在 Oracle.DataAccess.Client.OracleDataReader.GetDecimal(Int32 i) 在 Oracle.DataAccess.Client.OracleDataReader.GetValue(Int32 i) 在 Oracle.DataAccess.Client.OracleDataReader.GetValues(对象 [] 值) 在 System.Data.ProviderBase.SchemaMapping.LoadDataRow() 在 System.Data.Common.DataAdapter.FillLoadDataRow(SchemaMapping 映射) 在 System.Data.Common.DataAdapter.FillFromReader(DataSet 数据集, DataTable datatable, String srcTable, DataReaderContainer dataReader, Int32 startRecord, Int32 maxRecords, DataColumn parentChapterColumn, 对象 parentChapterValue) 在 System.Data.Common.DataAdapter.Fill(DataTable[] 数据表, IDataReader dataReader, Int32 startRecord, Int32 maxRecords) 在 Oracle.DataAccess.Client.OracleDataAdapter.Fill(DataTable[] dataTables,Int32 startRecord,Int32 maxRecords,IDbCommand 命令, CommandBehavior 行为)在 System.Data.Common.DbDataAdapter.Fill(DataTable dataTable)

这是我在 VB.Net 中的示例代码

Using comm = createCommand(strSql, CommandType.Text,60)
   Using Da = _providerFactory.CreateDataAdapter
       Da.MissingSchemaAction = MissingSchemaAction.Add
       Da.SelectCommand = comm
       Da.SelectCommand.CommandTimeout = 60
       Dim dt As New DataTable
       Da.Fill(dt)                  
       Return dt
   End Using
End Using

我正在尝试读取的示例值

792281625142643375935439503351.000000000000000000000000000012

我找到了各种其他链接,例如 this 一个可以解决我的问题,但没有一个对我有用。我愿意将值读取为字符串并稍后进行转换。

编辑 1:

数据库查询不受我控制,因此我无法编辑客户端传递的查询。此外,我使用工厂模式创建 DataAdapter 为 MySql、Oracle、DB2、Sqlite、Sqlserver 等多个数据库提供支持,因此编辑查询是不可行的。我的工具使用用户提供的查询获取数据并以 xml 格式提供输出。

编辑 2:

我尝试使用 Java 来获取数据,并且 resultset.getString("column_name") 可以很好地以字符串形式获取数据。我们在.Net中有类似的东西吗?

.Net 中提供的 DataReader.GetString() 不起作用。

【问题讨论】:

  • 你能发布其中一个大值吗?所以我们掌握了我们所说的维度。您尝试了哪些链接,它们有什么问题?
  • @DeveloperExceptionError:问题已更新。
  • @Mate 不,双精度只有 15 位。这也是我的第一个想法:(
  • 最好的处理方法是使用 BIGINT。然后将数字乘以 1xE30,这样所有数字都是整数。您可以简单地删除小数点并使用 BigInt 解析字符串。
  • @jdweng 转换将在获取数据后工作。它在获取数据时抛出错误。甚至 DataReader.GetString() 也不起作用。

标签: c# mysql vb.net oracle datatables


【解决方案1】:

由于该值太大而无法读取为 .NET Decimal,因此您必须在执行 MySqlDataReader 或使用 MySqlDataAdapter 读取它之前将其转换为数据库中的字符串。

将您的 SQL 更改为:

SELECT CAST(BigDecimalValue AS CHAR), ... FROM table ...

然后,当您读取此值时,它将是一个包含十进制数字的String。您将不得不“将值读取为字符串并稍后进行转换。”

【讨论】:

  • 查询不在我的控制之下。客户使用我的工具运行他们自己的查询。
  • @prem 在这种情况下,我不知道任何其他解决方法;因为该列的类型为DECIMAL,MySQL 连接器/NET 将尝试将其读取为decimal(然后因为它太大而失败)。
  • 是否可以在 .Net 中读取如此大的十进制值?如果我能得到一些不可能的链接,那也有帮助。
  • @prem 文档 msdn.microsoft.com/en-us/library/system.decimal.aspx 说“十进制值类型表示十进制数,范围从正数 79,228,162,514,264,337,593,543,950,335 到负数 79,228,162,514,264,337,593,543,950,335。”您的示例编号 792,281,625,142,643,375,935,439,503,351 是最大小数的十倍;因此,它不能被解读为Decimal。无法将此值读取为Decimal
  • @prem “查询不在我的控制之下”,但您确实有 strSQL。你不能解析 strSQL,如果问题列在那里,那么编辑 strSQL 以反映 Bradley Grainger 提供的 Cast
【解决方案2】:

据我所知,.NET Framework 本身目前不支持这么大的十进制值。

但是 stackoverflow 用户 Gigo 实现了自定义 .NET Big Decimal variant (Source code)。它还不是生产级,但适用于大多数场景。

我建议尝试他的变体并向存储库报告任何问题,以便他们能够修复它们。

【讨论】:

  • 我认为转换对我来说不是真正的问题。我无法读取该值。即使我尝试使用数据阅读器逐行读取并将结果存储为字符串,但它也会引发相同的错误。
猜你喜欢
  • 2015-06-16
  • 2013-10-14
  • 2011-01-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多