获取“读取器关闭时读取无效的尝试”

问题描述:

我已经得到了下面的代码(这里有可读性的伪值),其中第一个连接返回大量数据(成千上万行)。 SqlDataReader的读取逐一由reader.Read(),然后打开一个新的连接,以更新的每一行用新值:获取“读取器关闭时读取无效的尝试”

using (SqlConnection conn = new SqlConnection(connString)) 
    using (SqlCommand cmd = new SqlCommand("sp1", conn)) 
    { 
     cmd.CommandType = CommandType.StoredProcedure; 
     cmd.Parameters.AddWithValue("@param1", param1); 
     cmd.Connection.Open(); 
     using (SqlDataReader reader = cmd.ExecuteReader()) 
     { 
      while (reader.Read()) 
      { 
       try 
       { 
        string hash= utils.SHA256.Hashing((string)reader["firstRow"], saltValue); 
        using (SqlConnection conn2 = new SqlConnection(connString)) 
        using (SqlCommand cmd2 = new SqlCommand("sp2", conn2)) 
        { 
         cmd2.CommandType = CommandType.StoredProcedure; 
         cmd2.Parameters.AddWithValue("@param1", param1); 
         cmd2.Parameters.AddWithValue("@param2", param2); 
         cmd2.Connection.Open(); 
         cmd2.ExecuteNonQuery(); 
        } 
       } 
       catch (SqlException ex) 
       { 
        //something 
       } 
      } 
     } 
    } 

但它抛出一个错误:

[InvalidOperationException: Invalid attempt to call Read when reader is closed.] 
System.Data.SqlClient.SqlDataReader.ReadInternal(Boolean setTimeout) +640 
System.Data.SqlClient.SqlDataReader.Read() +9 

在开发环境中能正常工作,但这里只有几百行。它立即抛出错误,所以它不直接看起来像某种超时,但嘿 - 我不知道...

+0

什么行会失败? – CodingGorilla

+0

当在阅读器上调用Read时。 while(reader.Read()) – Thomas

+0

你可以用SQL在第一个SPROC中做这个吗? – MikeSmithDev

不知道它为什么会发生,但它是一个坏主意查询同时迭代到同一个数据库的实时连接。请记住,只要您使用DataReader迭代记录,连接就是活着的。

更糟糕的是打开然后关闭一个连接连续数千次。仅此一项就可以使任何数据库瘫痪。

更改您的逻辑,将您需要的值存储在本地变量中(结构无关紧要),然后仅使用一个连接来执行所需的所有存储过程。

例如:

using (SqlConnection conn = new SqlConnection(connString)) 
{ 
    conn.Open(); 

    List<string[]> values = new List<string[]>(); 
    using (SqlCommand cmd = new SqlCommand("sp1", conn)) 
    { 
     cmd.CommandType = CommandType.StoredProcedure; 
     cmd.Parameters.AddWithValue("@param1", param1); 
     using (SqlDataReader reader = cmd.ExecuteReader()) 
     { 
      while (reader.Read()) 
      { 
       try 
       { 
        string hash= utils.SHA256.Hashing((string)reader["firstRow"], saltValue); 
        string anotherValue = (string)reader["secondRow"]; 
        values.Add(new string[] { hash, anotherValue }); 
       } 
       catch (SqlException ex) 
       { 
        //something 
       } 
      } 
      reader.Close(); 
     } 
    } 

    if (values.Count > 0) 
    { 
     using (SqlCommand cmd2 = new SqlCommand("sp2", conn)) 
     { 
      cmd2.CommandType = CommandType.StoredProcedure; 
      cmd2.Parameters.AddWithValue("@param1", null); 
      cmd2.Parameters.AddWithValue("@param2", null); 
      values.ForEach(items => 
      { 
       cmd2.Parameters["@param1"].Value = items[0]; 
       cmd2.Parameters["@param2"].Value = items[1]; 
       cmd2.ExecuteNonQuery(); 
      }); 
     } 
    } 
    conn.Close(); 
} 

一个连接,一个要执行的命令的所有存储过程。真的不需要更多。

+3

“打开然后关闭连接数千”是相当便宜,如果您使用连接池。 –

+0

谢谢。做了一点改写,但很接近这一点 - 它的工作原理......虽然仍然不知道错误,但希望我不会再看到它! – Thomas

+0

欢呼@Thomas数据库上的重载可能导致一些内部超时,结果DataReader被关闭。现在你不会创建任何额外的重载,所以它不会发生。 :) –