如何使用SqlDataReader获取浮点数值?

12

在我的数据库中,我将NextStatDistanceTime值设置为浮点型。当执行"float time = reader.GetFloat(0);"代码时,它会报错:

系统无效转换异常

我该如何在这段代码中从SQL命令获取浮点值?

以下是我的代码:

using (SqlConnection conn = new SqlConnection(@"<myconnectionstring>"))
{
    float totaltime = 0;
    for (int i = startStationIndex; i < endStationIndex; i++)
    {
        SqlCommand command = new SqlCommand("SELECT NextStatDistanceTime FROM [MetroDatabase].[dbo].[MetroStation] WHERE StationIndex = " + i + "", conn);
        try
        {
            conn.Open();
            command.ExecuteNonQuery();
            using (SqlDataReader reader = command.ExecuteReader())
            {
                while (reader.Read())
                {
                    float time = reader.GetFloat(0);
                    totaltime = totaltime + time;
                    conn.Close();
                }
            }                        
        }
        catch (Exception ex)
        {
            result = ex.Message;
            Console.WriteLine(ex.Message);
        }
    }

}

3
数据库中的类型是什么? - Jon Skeet
@JonSkeet 他已经提到了,数据库中是“float”。 - Ranjit Singh
1
@RanjitSingh: 哎呀,看漏了。既然是这样,我真的希望它没问题... 我猜在数据库中它不是真正的浮点数。调用“reader.GetValue(0)”得到的结果很有趣 - 那是什么类型? - Jon Skeet
1
顺便说一下,你应该立刻开始使用参数化的SQL。 - Jon Skeet
哦,为什么不让数据库为您汇总这些值呢?获取所有值再将它们相加似乎有些奇怪... - Jon Skeet
7个回答

35

现在是时候来一张小表格了。

T-SQL 类型名称 .NET 等效类型 C# 类型名称 DataReader 方法
FLOAT System.Double double IDataReader.GetDouble()
REAL System.Single float IDataReader.GetFloat()

请注意,GetFloat 的名称是错误的,它应该是 GetSingle,因为 float 是一个特定于 C# 的名称。例如,在 VB.NET 中这个名称没有意义。

因此,如果您的数据库列的类型是 FLOAT,请使用 GetDouble 读取它,而不是 GetFloat。数据读取器方法不执行转换;有一个通用的 GetValue 方法可以将值获取为一个 object ,然后进一步转换。

顺便说一下,这不是唯一的细微差别——.NET 浮点类型支持denormalized values,而 T-SQL 类型则不支持,因此即使类型匹配,在您的 .NET 代码中也可能存在无法成功存储到数据库的浮点数。


你可以在这里找到该表格;-) - Tim Schmelter
@TimSchmelter:这是一个略微不同的表格,因为它描述了映射到ADO.NET SQL特定类型的过程。SqlSingle并不等同于System.Single。我可以在我的表格中包括它以完整起见,但是除非没有相应的.NET系统类型(比如SqlGeography),否则很少需要使用这些类型。但是,是的,这是另一层需要注意的转换。 - Jeroen Mostert

4

如您所见 这里 ,SQL Server的Float对应.NET中的Double,因此您需要使用GetDouble来获取数据:

double totaltime = 0;  // necessary, double is wider than float
// ...

while (reader.Read())
{
    double time = reader.GetDouble(0);
    totaltime = totaltime + time;
    // conn.Close(); no, not in this loop, should be closed in the finally or via using-statement
}

2

我的猜测是数据库返回了双精度值,尝试将其作为Double获取并转换为float(如果需要)。

float time= (float) reader.GetDouble(0);

0

可能是数据库类型和C#类型之间的精度不匹配。 尝试像这样进行转换:(float)reader.GetDouble(0);


0

你可以尝试:

float time = float.Parse(reader[0].ToString());

还要注意(虽然与你的问题无关),你不需要运行

command.ExecuteNonQuery();

0
 while (reader.Read())
 {
     object initialTime = reader["NextStatDistanceTime"];
     float time;
     float.TryParse(initialTime.ToString(), out time);

     totaltime = totaltime + time;
     conn.Close();
 }

试试这个,它会从数据库中获取时间并将其转换为 float 类型,你可以直接在 tryparse 中放入 reader["NextStatDistanceTime],但为了更清晰明了,我已经这样做了。

如果有任何问题,请告诉我。


@TimSchmelter 能解释一下吗? - Brendon
@JonSkeet 好的,那很有道理,否则它就无法转换为浮点数,并且在将其用作浮点数之前可能需要验证它,以检查它是否包含“,”或类似的内容。 - Brendon
@JonSkeet 好的,谢谢。我对他们使用的 .GetDouble 不熟悉,这也是我做出答案的原因...我会对其进行一些研究,并在将来的代码中使用它们。 - Brendon
@Brendon:因为你接受了OP不知道浮点数被映射到double的事实,并提供了使用字符串转换的解决方法。这在这种情况下可能有效,但可能会引起其他问题(将来)。字符串转换总是容易受到本地化问题的影响(例如,一个文化使用冒号作为小数分隔符,而另一个文化使用逗号)。而且效率也不高。 - Tim Schmelter
感谢 @TimSchmelter - Brendon
显示剩余4条评论

0

试试这个

convert.ToSingle(reader["NextStatDistanceTime"])

或者执行

double value = (double)reader["NextStatDistanceTime"]

SQL中的浮点数相当于C#中的双精度数,你可以在这里看到类似的映射


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接