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 を割り当てるときに行う変換の仮定があるかどうかわからないため、これを取り上げています。たとえば、 からTimeSpanへの暗黙的または明示的な変換はありませんlong

于 2012-06-10T15:07:30.100 に答える