【问题标题】:SQL Data Reader: Invalid attempt to read when no data is presentSQL 数据读取器:不存在数据时尝试读取无效
【发布时间】:2017-05-01 17:22:15
【问题描述】:

我正在尝试使用 SqlDataReader 运行查询,然后在消息框中显示结果,但我不断收到错误

不存在数据时尝试读取无效。

这是我的代码。

 public void button1_Click(object sender, EventArgs e)
 {
    string results = "";
    using (SqlConnection cs = new SqlConnection(@"Server=100-nurex-x-001.acds.net;Database=Report;User Id=reports;Password=mypassword"))
    {
         cs.Open();
         string query = "select stationipaddress from station where stationname = @name";
         using (SqlCommand cmd = new SqlCommand(query, cs))
         {
              // Add the parameter and set its value -- 
              cmd.Parameters.AddWithValue("@name", textBox1.Text);
              using (SqlDataReader dr = cmd.ExecuteReader())
              {
                   while (dr.Read())
                   {
                        label3.Text = dr.GetSqlValue(0).ToString();
                        results = dr.GetValue(0).ToString();
                        //MessageBox.Show(dr.GetValue(0).ToString());
                        //MessageBox.Show(results);
                    }
                    MessageBox.Show(results);
              }
         }
    } 
}

【问题讨论】:

  • 只是一个见解:您的查询文本不需要任何格式。换句话说,您不需要将文本传递给 string.Format()。您可以像这样简单地分配它:string query = @"select top 1 stationipaddress from station"。
  • 如果您的SELECT 没有返回任何数据,那么您对while (dr.Read()) 的调用将立即终止(没有什么可读取的!),但是两行之后,您仍然可以访问MessageBox.Show(dr.GetValue(0).ToString());会惨败……为什么这条线while (dr.Read())块之外?您应该将值读入块内部的字符串变量中,然后将其用于消息框....
  • 只是一个见解:您对 string.Format() 的使用表明您可能习惯于使用它将参数数据替换为查询。 这太不安全了! 它会导致 Sql Injection 漏洞。您需要改用参数化查询。了解他们。使用它们。如果您已经知道这一点并且我对此阅读过多,请忽略,否则请理解这是非常重要的。
  • 我认为您使用解决方案更新了您的问题,因此很难判断您做错了什么。如果其他人碰巧有同样的问题,他们将无法识别它。我建议不要使用解决方案更新问题中的代码。有点违背了整个目的。

标签: c# sql sql-server sqldatareader


【解决方案1】:

没错。
当您退出 while 循环时,DataReader 已到达加载数据的末尾,因此无法用于获取不存在的当前记录的值。

Read 方法将 SqlDataReader (dr) 推进到下一条记录,如果有更多行,则返回 true,否则返回 false。

如果您只有一条记录,您可以通过这种方式使用results 变量

MessageBox.Show(results);

现在,这将起作用,因为您的 sql 语句中有一个 TOP 1,但是,如果您有多个记录,它将仅显示最后一条记录的值。

正如 marc_s 在其评论中所指出的,如果您的表为空,则您的代码不会落入 while 循环中,因此您可能可以使用如下消息初始化结果变量:

 results = "No data found";

编辑:在下面看到您的评论,那么您应该以这种方式更改您的代码

.....
// Use parameters **ALWAYS** -- **NEVER** cancatenate/substitute strings 
string query = "select stationipaddress from station where stationname = @name";
using (SqlCommand cmd = new SqlCommand(query, cs))
{
    // Add the parameter and set its value -- 
    cmd.Parameters.AddWithValue("@name", textBox1.Text);
    using (SqlDataReader dr = cmd.ExecuteReader())
    {

        while (dr.Read())
        {
            label3.Text = dr.GetSqlValue(0).ToString();
            results = dr.GetValue(0).ToString();
        }
    }
}
.....

【讨论】:

  • 好的,我知道我必须把它放在while循环中!感谢您的帮助!
  • 我也在尝试使用文本框来获取站名,但它似乎不起作用。这是我的查询
  • string query = string.Format(@"select stationipaddress from station where stationname = '" + textBox1.Text + "'", textBox1.Text);
  • 请点击编辑按钮将此代码添加到您的原始问题中
  • 它似乎仍然无法正常工作 - 上面的编辑代码
【解决方案2】:

我在尝试获取我知道的 GUID 时遇到了类似的问题 - 我可以直接在 SQL Management Studio 中运行相同的 SQL 并获得我的结果。因此,我没有尝试将其作为 GUID 恢复(它保存在 char(35) 字段中,即使它确实是 GUID!),而是将其作为字符串恢复:

        SqlConnection sqlConn = null;
        string projId = String.Empty;
        string queryString = "SELECT * FROM project WHERE project_name='My Project'";

        try
        {
            sqlConn = new SqlConnection(connString);
            SqlCommand cmd = new SqlCommand(queryString, sqlConn);
            sqlConn.Open();

            SqlDataReader reader = cmd.ExecuteReader();
            if (reader.HasRows)
            {
                while (reader.Read())
                {
                    projId = reader.GetSqlValue(0).ToString();   // <-- safest way I found to get the first column's parameter -- increment the index if it is another column in your result
                }                    
            }
            reader.Close();
            sqlConn.Close();
            return projId;                
        }
        catch (SqlException ex)
        {                
            // handle error
            return projId;
        }
        catch (Exception ex)
        {
            // handle error
            return projId;
        }
        finally
        {
            sqlConn.Close();
        }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多