从SQLiteDataReader读取时,我遇到一些奇怪的行为,GetFieldType(0)返回typeof(Int64),GetValue(0)返回Int64,但GetInt64(0)失败并出现System.InvalidCastException异常。
我花了很长时间才重现这种行为:
using System;
using System.Data.SQLite;
using NUnit.Framework;
namespace Test
{
[TestFixture]
public class SQLiteType
{
[Test]
public void A()
{
var sqlConnection = new SQLiteConnection("Data Source=:memory:;Version=3;");
sqlConnection.Open();
var create = sqlConnection.CreateCommand();
create.CommandText = "CREATE TABLE FOO (x INTEGER)";
create.ExecuteNonQuery();
var insert = sqlConnection.CreateCommand();
insert.CommandText = "INSERT INTO FOO VALUES (?)";
var param = insert.CreateParameter();
param.Value = new TimeSpan(0); // NOTE INSERTING TIMESPAN DIRECTLY instead of .Ticks
insert.Parameters.Add(param);
insert.ExecuteNonQuery();
var select = sqlConnection.CreateCommand();
select.CommandText = "SELECT x FROM FOO";
var dr = select.ExecuteReader();
while (dr.Read())
{
var valueObject = dr.GetValue(0);
Assert.AreEqual(typeof (Int64), valueObject.GetType());
var valueType = dr.GetFieldType(0);
Assert.AreEqual(typeof (Int64), valueType);
var value = dr.GetInt64(0); // throws System.InvalidCastException
}
}
}
}
当通过将TimeSpan值直接插入INTEGER列(而不是例如可能更有意义的TimeSpan.Ticks)创建行时,似乎会发生这种情况。尽管如此,datareader仍然告诉我该列是Int64。
我不确定SQLiteDataReader的合约是什么,但我之前曾假设如果GetFieldType()返回typeof(Int64),那么GetInt64()不会失败。也许情况并非如此? (GetValue()仍返回Int64似乎很奇怪)也许它是SQLite独特的动态类型系统的工件。
当然不难避免,但出于教学原因,我只是好奇为什么会发生这种情况?
答案 0 :(得分:1)
根本原因可能与SQLite如何处理类型有关:
http://www.sqlite.org/datatype3.html#affinity
即便如此,这对我来说似乎是个错误;如果:
dr.GetValue(0).GetType() == typeof(System.Int64)
然后它应该遵循dr.GetInt64(0)
不会抛出异常。我会发送电子邮件至sqlite-users@sqlite.org,如下所述:http://www.sqlite.org/src/wiki?name=Bug+Reports
请注意,如果你更换:
param.Value = new TimeSpan(0);
与
param.Value = new TimeSpan(0).Ticks;
然后
var value = dr.GetInt64(0);
工作正常。我提出这个问题是因为我不确定在分配TimeSpan时是否有任何转换假设。例如,没有从TimeSpan
到long
的隐式或显式转换。