【问题标题】:How to get double value with SqlDataReader如何使用 SqlDataReader 获得双倍值
【发布时间】:2022-01-20 09:14:19
【问题描述】:

我正在尝试从 sql 数据库中读取数据。当我运行代码时,它会在读取数据的位置出现错误。

“System.InvalidCastException:指定的强制转换无效。”

我得到一个错误。我研究了我的错误,但找不到适合我的解决方案。虽然我编写的查询文本在 ssms 中有效,但在代码中无效。

 private void pbx_frame_MouseUp(object sender, MouseEventArgs e) //
    {
        //take cropped image to picture box of crooped images
        try
        {
            string[] resim = lbx_raw_image.SelectedItem.ToString().Replace(':','.').Split('.'); 
            string sorgu_sql = "Data Source=DESKTOP-OON7EET\\SQLEXPRESS;Initial Catalog=Target;Integrated Security=True;"; //sql bağlantısı kuruldu
            //string query = "SELECT * FROM MP_Data$ WHERE time= '19.53.06'"; //'" + lbx_raw_image.SelectedItem.ToString() + "'"; //time=19.53.06 tek bir veriyi çağrır. muhtemelen yorum haline getirilen kısım olacaktı.
            string query = "SELECT * FROM MP_DATA_15_mayıs_2019$ WHERE time='" + lbx_raw_image.SelectedItem.ToString() + "'"; //12.50.23
            DB_islem db = new DB_islem(sorgu_sql, query); // 
            
            pic_info_from_MP = db.Raw_Image(pic_info_from_MP);      



    public Target Raw_Image(Target pic_info) 
    {
        sql.Open();
       
        sql_read = sql_command.ExecuteReader();

        //while (sql_read.Read())
        if (sql_read.Read())
        {
            pic_info.lat = sql_read.GetDouble(0);
            pic_info.lon = sql_read.GetDouble(1);
            pic_info.alt = sql_read.GetDouble(2);
            pic_info.yaw = sql_read.GetDouble(3);
        }

        sql.Close();

        return pic_info;
    }

解决方案:

ALTER TABLE table1(name of table) ALTER COLUMN clmn1(name of column) float(datatype);

我使用上述查询确定了每一列的数据类型。帮我调用了所需的数据。

【问题讨论】:

  • 如果 time = '12.50.23',为什么你在代码前面替换冒号,而不是在查询中?并参数化您的查询以确保安全性、性能和准确性
  • 我猜这是你的 alt 值。 SSMS 可能会处理这个问题,但在 c# 中,double 被限制为 16 位,因此这个值有太多小数。尝试使用十进制类型。
  • 请显示表定义
  • 正如@LocEngineer 所说,alt 列中的值可能太长。此外,您可以在其他列上有更多有问题的值,因为您使用了 where 子句,我们看不到所有内容。

标签: c# sql ssms sqldatareader


【解决方案1】:

我要求表定义的原因是因为在 DB 端有特定的列类型映射到 C# 端的特定数据类型。发布的屏幕截图不足以实际确定列类型。 lat 和 long 不是real,否则它们会被截断,但除此之外我们不能说

广义地说:

  • 如果您使用过real 列类型,请致电GetFloat(..)
  • 如果您使用过float 列类型,请致电GetDouble(..)
  • 如果您使用过decimal(或numeric)列类型,请致电GetDecimal(..)

GetXxx 不会为您转换,因为它会进行拆箱强制转换。如果您的读者在第 0 列中有 decimal,您只能在其上调用 GetDecimal。您不能调用 GetDouble 并期望您真的十进制转换为双精度,原因与这不起作用:

object o = 0.1m; //decimal boxed inside object
double d = (double)o;

拆箱转换和转换转换是不同的东西。如果您希望您的对象中的小数点为双精度,则必须转换两次,一次拆箱,一次转换:

object o = 0.1m; //decimalboxed inside object
double d = (double)(decimal)o;

同样,如果您在阅读器第 0 列中的内容是 decimal 并且您想要 double,您必须将其作为小数,因为这就是它的真正含义,然后将其转换:

var dbl = (double)reader.GetDecimal(0);

简单规则:

  • 根据真实情况拉出来,然后转换

至于你有什么,我们不知道;你的yaw 可以是real,不能是GetDouble'd(必须是GetFloat'd)。你的alt 可能是一个小数(你真的需要高度到十分之一皮米/皮英尺吗?)不能是GetDouble'd(必须是GetDecimal'd).. 但你有自己解决这个问题的必要信息。

如果所有其他方法都失败并且上述内容完全超出您的想象“尝试将 GetDouble 更改为 GetDecimal 以获取不起作用的行。如果这不起作用,请尝试将其更改为 GetFloat。如果没有”行不通,提供表定义,我们会告诉你它应该是什么”

更新:您表示它们都是 varchar。就我个人而言,我会将它们转换为浮动或真实 - 打开 SSMS,设计表格,将列类型更改为例如浮动并保存表格。然后他们可以被GetDouble'd

【讨论】:

  • 感谢您的评论。正如你所说,我查看了表定义,它显示所有列的 nvarchar。我将excel表导入数据库。可能这种数据类型是默认类型,因为我没有选择任何数据类型。现在,是时候提出真正的问题了。如何从数据库中调用 varchar 数据或如何更改列的数据类型?
  • 就我个人而言,我认为我会更改表格,使列全部为 FLOAT,这也会转换数据。如果大约 7 位小数,您可以对所有列使用 REAL,并将存储数据所需的字节减半
【解决方案2】:

首先,您应该只使用参数执行查询。 其次,我们不知道您的表架构 - 请出示它。

但很可能您存储此值的方式存在问题。 GetDouble 不进行任何转换,因此您的数据应该已经保存为 double。

此外,全球化可能存在问题。你应该做的是:

using System.Globalization;
//...

double result = double.NaN;

if(!sql_read.IsDbNull(0))
{
    string s = sql_read.GetString(0);
    result = Convert.ToDouble(s, CultureInfo.InvariantCulture);
} 

【讨论】:

  • 我非常不同意将所有内容都通过字符串绊倒是某人“应该做的”
  • 特别是因为你可以将Object传递给Convert.ToDouble,所以Convert.ToDouble(dr.GetValue(i))
  • 我不同意 - 小数点分隔符可能存在问题。在与不同文化玩耍时。
猜你喜欢
  • 2013-03-30
  • 2011-01-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-17
  • 1970-01-01
相关资源
最近更新 更多