SqlDataReader HasRows=True 但没有数据

SqlDataReader HasRows=True but no data

我正在连接到 SQL Server 2012 数据库以根据 ID 查询单个值。 (可能值得一提的是,这个数据库位于我开发机器的另一个大陆的服务器上,因此延迟非常高。大约 100 毫秒)。

查询似乎执行成功。 SqlDataReader 对象的HasRows 属性 设置为true,所以我尝试使用值来赋值给一个变量。当我 运行 程序正常运行时,我遇到异常消息 'Given key was not present in the dictionary'。如果我停止执行并检查 SqlDataReader 对象,并枚举结果。首先我被告知 'enumeration yielded no results' 然后当我继续执行时我得到一个不同的异常消息 'invalid attempt to read when no data is present'

这里是有问题的代码:

SqlConnection sql_conn = new SqlConnection(ConnectionString);
SqlCommand sql_cmd = new SqlCommand(String.Format("select ItemType from ItemTable where ItemID='{0}'", item_id), sql_conn);

Console.WriteLine(sql_cmd.CommandText);

sql_conn.Open();

SqlDataReader rdr = sql_cmd.ExecuteReader();

rdr.Read();

if (rdr.HasRows) //True
{
    item_type= TypesMap[rdr["ItemType"].ToString()]; //Either 'given key not found in dictionary' or 'invalid attempt to read when no data is present'
}

我在 SQL Server Management Studio 中执行了 SQL 语句并且成功了。我已经尝试将 ItemID 硬编码到 C# 代码中的语句中,但仍然存在相同的错误。

我还能做些什么来调试这个?一切似乎都很好,直到我尝试访问查询结果。

您必须调试:似乎TypesMap 没有 从数据库中读取的密钥:

// Wrap IDisposable into using
using (SqlConnection sql_conn = new SqlConnection(ConnectionString)) {
  // Make SQL readable
  // Make SQL parametrized (and not formatted) when it's possible
  String sql = 
    @"select ItemType 
        from ItemTable 
       where ItemID = @prm_ItemId"; 

  // Wrap IDisposable into using
  using (SqlCommand sql_cmd = new SqlCommand(sql, sql_conn)) {
    // I don't know ItemID's type that's why I've put AddWithValue 
    sql_cmd.Parameters.AddWithValue("@prm_ItemId", item_id);

    // Wrap IDisposable into using
    using (SqlDataReader rdr = sql_cmd.ExecuteReader()) {
      // rdr.HasRows is redundant - rdr.Read() returns true if record has been read
      if (rdr.Read()) {
        String key = Convert.ToString(rdr.GetValue(0));
        // Put break point here: what is the "key" value?
        item_type = TypesMap[key];
      }
    }
  } 
}

编辑: 正如 Luke 在评论中提到的,错误的原因是密钥比较预计 不区分大小写 ,所以修改是为了解释.Net如何比较键:

var TypesMap = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

...
TypesMap.Add("aBc", "xyz"); 
String test = TypesMap["Abc"]; // return "xyz"; notice "aBc" and "Abc"

正如德米特里指出的那样,'given key not found...' 不是数据库而是字典。 下面我添加了一个简单的检查以确保密钥在字典中 - 如果是那么我们可以分配给 item_type.

此外,如果 HasRows() 未按预期运行,请尝试以下操作。这是我从数据库读取的标准方式:

using (SqlDataReader results = sql_cmd.ExecuteReader(CommandBehavior.CloseConnection))
{
    while (results.Read())
    {
        string Key = rdr["ItemType"].ToString();
        if (TypesMap.ContainsKey(Key))
            item_type = TypesMap[Key];       
    }
}

我转换了:

dto.Id = (int)record["Id"];  

收件人:

dto.Id = (int)record[0]; 

这对我有用。