【问题标题】:"Invalid attempt to call Read when reader is closed" when using a SqlDataReader使用 SqlDataReader 时“读取器关闭时调用读取的尝试无效”
【发布时间】:2012-01-24 02:34:21
【问题描述】:

1) 我有以下代码:

private static sqlDataReader gCandidateList = null;

public SqlDataReader myCandidateList
{
    set
    {
        gCandidateList = value;
    }
    get
    {
        return gCandidateList;
    }
}

2) 在FormA我有:

sqlConn.ConnectionString = mySettings.myConnString;
sqlConn.Open();
SqlCommand cmdAvailableCandidate = new SqlCommand(tempString, sqlConn);
SqlDataReader drAvailableCandidate = cmdAvailableCandidate.ExecuteReader();
mySettings.myCandidateList = drAvailableCandidate;
sqlConn.Close();

3) 在 FormB 中,我想重用保存在 myCandidatList 中的数据,所以我使用:

SqlDataReader drCandidate = mySettings.myCandidateList;
drCandidate.Read();

4) 然后我收到错误“读取器关闭时调用读取无效。”

5) 我在上面 (3) 中尝试了 mySettings.myCandidateList.Read() 并再次收到相同的错误消息。

6) 如何重新打开 SqlDataReader drCandidate 来读取数据?

7) 非常感谢您的建议和帮助。

【问题讨论】:

  • 静态 DataReader 绝不是个好主意。

标签: c# sqldatareader


【解决方案1】:

一旦连接为closeddisposed,您将无法阅读阅读器。如果您想稍后在代码中使用这些行(获取结果),您需要创建一个 ListDataTable

例如,

System.Data.DataTable dt = new System.Data.DataTable();
dt.Load(drAvailableCandidate);

【讨论】:

    【解决方案2】:

    如果您想在后期使用数据读取器,您必须将其指定为 ExecuteReader 方法的参数。您在 FormA 中的代码应更改如下。

    sqlConn.ConnectionString = mySettings.myConnString;  
    sqlConn.Open();  
    SqlCommand cmdAvailableCandidate = new SqlCommand(tempString, sqlConn);  
    SqlDataReader drAvailableCandidate = cmdAvailableCandidate.ExecuteReader(CommandBehavior.CloseConnection);  
    mySettings.myCandidateList = drAvailableCandidate;  
    sqlConn.Close(); 
    

    确保在使用数据读取器后将其丢弃,因为与数据库的连接将保持打开状态,直到数据读取器关闭。最好如下更改 FormB 中的代码。

    using (mySettings.myCandidateList)
    {
    mySettings.myCandidateList.Read();  
    }
    

    【讨论】:

      【解决方案3】:

      在尝试读取阅读器之前,您正在关闭连接。那是行不通的。

      【讨论】:

        【解决方案4】:

        当您对 SqlConnection 对象 (sqlConn.Close();) 调用 Close 时,它​​会关闭连接和您的数据读取器。这就是当您尝试从 FormB 读取 SqlDataReader 时收到错误的原因。

        您需要做的是更改myCandidateList 属性的定义,以返回您从drAvailableCandidate 阅读器中提取的数据的表示形式。

        基本上您需要做的是遍历drAvailableCandidate 对象中的行,提取值并将它们缓存在您的属性中以供以后检索。

        【讨论】:

          【解决方案5】:

          只是为了补充已经给出的答案,如果您使用的是 async/await,那么通过不等待 SqlConnection 的 using 块内的操作很容易被抓住。比如,做如下可以报错

          public Task GetData()
          {
              using(new SqlConnection(connString))
              {
                  return SomeAsyncOperation();
              }
          }
          

          这里的问题是我们没有等待 using 内部的操作,因此它在我们实际执行底层异步操作之前就被处理掉了。相当明显,但之前已经抓住了我。

          正确的做法是在 using 中等待。

          public async Task GetData()
          {
              using(new SqlConnection(connString))
              {
                  await SomeAsyncOperation();
              }
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-08-26
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-08-29
            • 2016-01-29
            • 1970-01-01
            相关资源
            最近更新 更多