使用来自Sap.Data.SQLAnywhere.v4.5数据提供程序的SACommand
时,某些简单查询无法执行。 (因此,连接到SAP SQL Anywhere 17数据库。)
好像数据提供者错误地检索了结果集列的类型,然后尝试了无效的强制转换。
通过示例
using (var cmd = new SACommand(@"select 'Test' + :p", cnx))
{
cmd.Parameters.AddWithValue(":p", " Test");
using (var reader = cmd.ExecuteReader())
...
}
ExecuteReader
失败,出现SAException : Cannot convert 'Test Test' to numeric
。
using (var cmd = new SACommand(@"select case when 0 = 1 then :p1 else :p2 end", cnx))
{
cmd.Parameters.AddWithValue(":p1", "odd");
cmd.Parameters.AddWithValue(":p2", "normal");
using (var reader = cmd.ExecuteReader())
...
}
ExecuteReader
失败,出现SAException : Cannot convert 'normal' to integer
。
using (var cmd = new SACommand(@"select d.HighScale + :p from DecimalTable d", cnx))
{
cmd.Parameters.AddWithValue(":p", _decimalTestValue);
using (var reader = cmd.ExecuteReader())
{
Assert.That(reader.Read(), Is.True, "No row returned");
object value = null;
Assert.That(() => value = reader.GetValue(0), Throws.Nothing, "Failed reading value");
Assert.That(value, Is.TypeOf<decimal>().And.EqualTo(_decimalTestValue * 2m),
"Unexpected value read");
}
}
此操作失败,因为检索了double
而不是decimal
,并在此过程中丢失了一些数字。
在数据提供者内部进行调试时,似乎是由于SADataReader
导致的失败,Init
方法分别检索了numeric
列类型而不是varchar
, integer
列类型而不是varchar
,以及double
列类型而不是decimal
。
然后,它将无法读取该行,或者在以后的情况下导致精度损失。
这里是完整的gist。
仅读取表列而不进行任何示例计算时,不会发生此问题。我无法通过使用Interactive SQL和局部变量(用于模拟参数)来重现它。
到目前为止,我发现的唯一解决方法是在整个表达式或参数周围添加显式强制转换。但这很不方便,尤其是当您实际上不是在编写SQL而是使用某些Linq提供程序时。
这些测试源自ORM测试套件,并且它们在许多其他数据库(例如SQL Server,Oracle,PostgreSQL,MySQL,SQLite等)上均成功。 (在Firebird的情况下,Firebird也有类似的麻烦,并且ORM已经存在一个肮脏的技巧,可以在SQL中即时注入强制类型转换。我宁愿不必复制它。)
此数据提供程序中是否需要调整任何设置,以便对结果集进行更好的列类型推断?
我发现了这个other question,它在另一个查询案例中看起来也很麻烦,但是数据库版本比较旧。不幸的是,它没有有用的答案。
我也在SAP site上问了这个问题,到目前为止,还没有答案。