从 C# 中的 SQLite 数据库获取 REAL/DOUBLE 类型的值的好方法是什么

问题描述

我正在尝试获取类型为 REAL 的特定列的值,并希望将其保存在 doublefloat 中。 >

问题是,到目前为止我尝试过的所有方法要么只返回一个整数,要么出现错误指定的强制转换无效。例如,如果数据库中的值是 1,99,我会得到 1。调试器说它仍然是 double 类型。

我尝试过的:

public static void GetDouble()
{
    sqliteConnection databaseConnection = new sqliteConnection($"Data Source=.\\val.sqlite;Version=3;");
    sqliteCommand sqlCommand = databaseConnection.CreateCommand();
    sqlCommand.CommandText = $"SELECT * FROM doubles";
    databaseConnection.open();

    sqliteDataReader sqlReader = sqlCommand.ExecuteReader();
    while (sqlReader.Read())
    {
        // expected values: 1,1 | 8,66 | 0,64 | 0,82 | 1,9 | 0,89 | 0,52 | 1,35 | 4,32 | 1,66

        double nbr = (double)System.Convert.Todouble(sqlReader["Kdratio"]); // gives me: 1 | 8 | 0 | 0 | 1 | 0 | 0 | 1 | 4 | 1

        // double nbr = sqlReader.GetDouble(sqlReader.Getordinal("Kdratio")); // specified cast is not valid
        // double nbr = sqlReader.GetDouble(5); // specified cast is not valid
        // double nbr = (double)sqlReader["Kdratio"]; // gives me: 1 | 8 | 0 | 0 | 1 | 0 | 0 | 1 | 4 | 1
        // float nbr = (float)sqlReader["Kdratio"]; // specified cast is not valid
        // float nbr = (float)System.Convert.Todouble(sqlReader["Kdratio"]); // gives me: 1 | 8 | 0 | 0 | 1 | 0 | 0 | 1 | 4 | 1
        // string nbr = ((double)sqlReader.GetDouble(5)).ToString("#,#",CultureInfo.InvariantCulture); // specified cast is not valid

        System.Console.WriteLine(nbr);
    }
    databaseConnection.Close();
}

我实际上尝试了很多组合,但都没有奏效。 我期待

double nbr = (double)System.Convert.Todouble(sqlReader["Kdratio"]);

工作,因为在其他方法中我收到不同的值,例如

Name = sqlReader["Name"].ToString()
OnlineTimeMinutes = System.Convert.ToInt32(sqlReader["OnlineTimeMinutes"])

但是双打似乎给我带来了很多麻烦。

那么我怎样才能得到两位小数的正确值呢?

解决方法

好吧,两天后我想通了。然而,我觉得这不是(或不应该)是解决此问题的正确方法。

这个,只有这个,给我返回了正确的值。

sqlReader.GetString(sqlReader.GetOrdinal("KDRatio"));

我再次仔细检查了这些值是否正确写入数据库。将它们作为 floatdouble 传入,当我使用

检查 Type 时
System.Console.WriteLine(sqlReader["KDRatio"].GetType().Name);

在这两种情况下都返回“Double”。

奇怪的是,我不能像预期的那样使用 reader.GetFloat()reader.GetDouble() 吗?对我来说看起来像是一个错误,读取双精度或浮点数的唯一方法是将其作为字符串读取。无论如何,它现在可以工作了。

最终使用了这个:

double n = double.Parse(sqlReader.GetString(sqlReader.GetOrdinal("KDRatio")));

编辑:

纯粹是偶然发现了一些东西。我使用 DB Browser 检查我的数据库中的值,我注意到数据库中的值是否只有 00's 在小数部分,例如 74.00,然后用句点写入值,我可以使用 GetDouble() 就好了。 GetString() 然后会再次给我一个异常,强制转换无效。如果它还有其他东西,所以 74,32,那么它是用逗号写的,我只能将其作为字符串读取。

这可能是 SQLite's Dynamic Typing 发挥作用的地方。它可能会弄乱我传入的 double 并且正在改变类型或其他东西。没有解释为什么我在检查时仍然得到双重返回作为类型,但有趣的行为..

所以,现在我最终使用了这个:

double n;
try { n = double.Parse(sqlReader.GetString(sqlReader.GetOrdinal("KDRatio"))); }
catch { n = sqlReader.GetDouble(sqlReader.GetOrdinal("KDRatio")); }
,

这似乎是 SQLite 特性的某种组合 - 即类型亲和性、灵活的类型及其对数字文字的处理(忽略文化并需要 '.' 作为十进制分隔符)。

https://sqlite.org/datatype3.html#type_affinity

https://sqlite.org/quirks.html#flexible_typing

https://sqlite.org/lang_expr.html#literal_values_constants_

您的列可能具有文本关联性。当您尝试将它们作为数字读取并遇到“,”字符时,SQLite.NET 库可能正在执行截断。

为了避免您当前的解决方法,我会尝试重新定义 SQLite 中的列以确保它是 NUMERIC 或 REAL 关联,并使用“。”而不是“,”作为您的小数点分隔符。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...