SQLiteDataReader GetFieldType()返回Int64,但在GetInt64()上失败 - 这是一个错误或功能吗?

时间:2012-06-10 14:14:04

标签: database sqlite

从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独特的动态类型系统的工件。

当然不难避免,但出于教学原因,我只是好奇为什么会发生这种情况?

1 个答案:

答案 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时是否有任何转换假设。例如,没有从TimeSpanlong的隐式或显式转换。