问题描述
我正在尝试获取类型为 REAL 的特定列的值,并希望将其保存在 double 或 float 中。 >
问题是,到目前为止我尝试过的所有方法要么只返回一个整数,要么出现错误:指定的强制转换无效。例如,如果数据库中的值是 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"));
我再次仔细检查了这些值是否正确写入数据库。将它们作为 float 和 double 传入,当我使用
检查 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 关联,并使用“。”而不是“,”作为您的小数点分隔符。