0

从 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)来创建行时,似乎会发生这种情况。尽管如此,数据读取器仍然告诉我该列是 Int64。

我不确定 SQLiteDataReader 的合同是什么,但我之前假设如果 GetFieldType() 返回 typeof(Int64),那么 GetInt64() 应该不会失败。也许不是这样?(GetValue() 仍然返回一个 Int64 似乎很奇怪)也许它是 SQLite 独特的动态类型系统的产物。

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

4

1 回答 1

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

于 2012-06-10T15:07:30.100 回答