指定的格式无效"当从OracleDataAdapter.Fill()填充数据表时

本文关键字:Fill OracleDataAdapter 填充 数据表 当从 格式 无效 quot | 更新日期: 2023-09-27 18:05:40

我似乎在Google(或StackOverflow)上找不到这个问题,这真的让我很惊讶,所以我把它放在这里帮助那些有同样情况的人。

我有一个SQL查询在Oracle SQL Developer上运行良好,但是当我使用adapter.Fill(table)通过C#运行它来获得结果时,我得到Specified cast is not valid错误(System.InvalidCastException)。

下面是c#代码的精简版本:

var resultsTable = new DataTable();
using (var adapter = new OracleDataAdapter(cmd))
{
    var rows = adapter.Fill(resultsTable);  // exception thrown here, but sql runs fine on Sql Dev
    return resultsTable;
}
下面是SQL的简化版本:
SELECT acct_no, market_value/mv_total
FROM myTable
WHERE NVL(market_value, 0) != 0
AND NVL(mv_total, 0) != 0

如果我删除除法子句,它不会出错-所以它是特定于此的。但是,market_value和mv_total的类型都是Number(19,4),并且我可以看到Oracle适配器期待一个小数,那么发生了什么类型的转换呢?为什么它在SqlDev上工作,而不是在c#中?

指定的格式无效"当从OracleDataAdapter.Fill()填充数据表时

回答我自己的问题:

看来Oracle的数字类型比c#的小数类型可以容纳更多的小数位数,如果Oracle试图返回超过c#可以容纳的小数位数,它会抛出InvalidCastException。

解决方案吗?

在sql中,将任何可能有太多小数点的结果四舍五入到合理的位置。所以我这样做:

SELECT acct_no, ROUND(market_value/mv_total, 8)  -- rounding this division solves the problem
FROM myTable
WHERE NVL(market_value, 0) != 0
AND NVL(mv_total, 0) != 0

它成功了。

的结论是:Oracle数字类型和c#十进制之间不兼容。限制Oracle的小数点,以避免无效的强制转换异常。

希望这对其他人有帮助!

我知道这个帖子真的很老了。然而,我有一个类似的问题。

最好的解决方案我必须使用Oracle方法TO_BINARY_DOUBLE在Oracle十进制列

我知道这个问题已经有人回答了,但是我还发现了另一个我也使用的替代方法。我在给我带来麻烦的场地上使用了CAST。

基于OP的SELECT命令:

SELECT acct_no, CAST((market_value/mv_total) AS DECIMAL(14,4))  -- CAST to decimal here
FROM myTable
WHERE NVL(market_value, 0) != 0
AND NVL(mv_total, 0) != 0

解决这个问题更方便的方法是在OracleDataAdapter中使用SuppressGetDecimalInvalidCastException:

var table = new DataTable();
await using var connection = new OracleConnection(connectionString);
var command = new OracleCommand(queryString, connection)
{
    CommandTimeout = commandTimeout
};
using var adapter = new OracleDataAdapter(command) { SuppressGetDecimalInvalidCastException = true };
await Task.Run(() => adapter.Fill(table));

来自文档:

该属性指定是否抑制InvalidCastException如果Oracle NUMBER值,则返回一个四舍五入的28精度值精度大于28。