【问题标题】:SQLiteDataReader type affinity bug?SQLiteDataReader 类型亲和力错误?
【发布时间】:2018-11-30 06:17:38
【问题描述】:

SQLite 可以在任何其他类型的列中存储任何类型的值。当我尝试使用 SQLiteDataReader 从 .net 应用程序读取此类不同类型的值时,即使我尝试将其作为对象读取,它也会执行转换为列定义的类型。这是一个例子:

using System;
using System.Data.SQLite;

namespace SqliteTypeAffinityTest
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:"))
            {
                // advise from @Shawn to use NoVerifyTypeAffinity does not help, neither separate nor combined with default

                // connection.Flags = SQLiteConnectionFlags.NoVerifyTypeAffinity;
                // connection.Flags = connection.Flags | SQLiteConnectionFlags.NoVerifyTypeAffinity;

                connection.Open();

                using (var cmd = new SQLiteCommand(connection))
                {
                    cmd.CommandText = "CREATE TABLE t(b BLOB)";
                    cmd.ExecuteNonQuery();

                    cmd.CommandText = "INSERT INTO t(b) VALUES (x'FF')";
                    cmd.ExecuteNonQuery();

                    cmd.CommandText = "INSERT INTO t(b) VALUES ('FF')";
                    cmd.ExecuteNonQuery();

                    cmd.CommandText = "SELECT b, typeof(b) AS type FROM t";
                    using (var reader = (SQLiteDataReader)cmd.ExecuteReader())
                    {
                        reader.Read();

                        object t1 = reader.GetValue(0);
                        string sqliteType1 = reader.GetString(1);

                        reader.Read();

                        object t2 = reader.GetValue(0);
                        string sqliteType2 = reader.GetString(1);

                        Type netType1 = t1.GetType();
                        Type netType2 = t2.GetType();

                        Console.WriteLine("sqlite type #1: {0}, .net type #1: {1}", sqliteType1, netType1);
                        Console.WriteLine("sqlite type #2: {0}, .net type #2: {1}", sqliteType2, netType2);
                    }
                }
            }

            Console.WriteLine("done");
            Console.Read();
        }
    }
}

控制台输出将是:

sqlite type #1: blob, .net type #1: System.Byte[]
sqlite type #2: text, .net type #2: System.Byte[]

请注意,.net 类型 #2 是 System.Byte[](SQLite 类型是文本!),但我希望它是 System.String。

有没有办法将这个值读取为字符串?我知道我也可以像我的示例中那样请求值类型并在阅读后执行一些转换,但我想避免它。

在@MikeT 回复后,编辑#1 在我的问题中更正确。我不是在寻找将列读取为字符串的方法。我需要用自己的类型读取每个值。所以在我的示例中,t1 必须保持为 byte[],但 t2 必须是字符串。我更新了我的示例以使其更加明确(以前有 1 行有两个 BLOB 列)。

编辑 #2 包括带有“使用”的完整测试文本,以使使用的库更明显并且更容易重现

【问题讨论】:

  • "SQLite 可以在任何其他类型的列中存储任何类型的值。"哇,这听起来很奇怪和违反直觉。它是否旨在保留有关实际存储的信息类型的信息?你有任何相关的链接吗? (说实话,这听起来真的,真的是个坏主意,但那是另一回事。)
  • 其实我看到这里有一些相关信息:sqlite.org/datatype3.html
  • 我强烈怀疑是驱动程序在执行转换 - 我希望在连接字符串中有某种方法可以禁用它,但是I can't see anything
  • @JonSkeet 我真的很高兴收到您的 3 条评论!您的最后一个链接是 DevArt 库,不确定,但我认为它们可能有一些特定的连接字符串选项,与 System.Data.SQLite 库中的不同。我已经对 GetValue 方法进行了反编译(然后在这里找到了它 - system.data.sqlite.org/index.html/artifact/400bce215e000cea),看起来有一些东西可以由 SQLiteConnectionFlags 驱动。我已经尝试了一些,但现在没有运气。但是您对此的关注给了我力量,我想我会尝试更多地调试它!
  • 啊 - 由于缺少 using 指令等,不清楚您使用的是哪个。这就是 minimal reproducible example 真正有帮助的地方。鉴于有多个 SQLite 驱动程序可用,我强烈建议您在问题中明确说明您使用的是哪一个。

标签: c# .net sqlite system.data.sqlite


【解决方案1】:

第三方 SQLite 工具通常不能很好地表示 Blob。但是,我相信使用hex(the_value) 将使它们合理(原文如此)可读。

例如考虑表格(同一列中的文本和 Blob,尤其是对于 Jon :)):-

使用(由于日期错误):-

SELECT hex(data) FROM convdt;

产量:-

附:使用 x'FF00FE01FD02' 插入(插入到类型为 TEXT 的亲和力的列中) - 可以使用quote函数返回X'FF00FE01FD02'

或处理您可以使用的不同列类型:-

SELECT typeof(data), CASE WHEN typeof(data) = 'blob' THEN hex(data) ELSE data END AS data FROM convdt;

然后得到:-

【讨论】:

  • 感谢您的回答,但很抱歉我不能接受。这不是我要寻找的。更新查询会将所有行中的所有值转换为某个指定的类型。但我需要知道每一行的值及其类型。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-10
  • 2013-08-19
  • 2015-10-28
  • 2016-05-31
相关资源
最近更新 更多