【问题标题】:There is already an open DataReader associated with this Command which must be closed first已经有一个与此命令关联的打开的 DataReader 必须先关闭
【发布时间】:2012-02-19 20:40:13
【问题描述】:

这是我的代码。

/// <summary>
/// Method calls stored procedure and fills DataSet of contacts associated with Lead
/// </summary>
/// <param name="leadID">The ID associated with a Lead</param>
/// <returns>contacts list as DataSet</returns>
public static DataSet GetContactResultSetByLead(int leadID)
{
    SqlCommand Sqlmd = new SqlCommand("dbo.proc_contact");
    Sqlmd.CommandType = CommandType.StoredProcedure;
    Sqlmd.Parameters.Add("@LeadInfoID", SqlDbType.Int).Value = leadID;

    Sqlmd.Connection = m_ConStr;
    SqlDataAdapter da = new SqlDataAdapter(Sqlmd);

    DataSet data = new DataSet();
    try
    {
        da.Fill(data);
    }

    finally
    {
        m_ConStr.Close();
    }

    return data;
}

【问题讨论】:

  • 更改这一行 Sqlmd.Parameters.Add("@LeadInfoID", SqlDbType.Int).Value = leadID;到 Sqlmd.Parameters.AddWithValue("@LeadInfoID", leadID);如果您想保留 Global Connect,请检查该连接的状态(如果打开,然后在使用之前将其关闭)。重构您的代码并使用有意义的变量名称......!将你的 Connection 包裹在 using() {}
  • Sqlmd 将在 da.Fill 调用期间执行。 m_ConStr 似乎是一个名称不佳的变量 - 它似乎是指连接本身,而不是连接字符串。

标签: c# datareader


【解决方案1】:

您的问题是您显然有一个m_ConStr 的实例;如果同时调用该方法,则只有其中一个能够使用该连接,而另一个将失败并出现您收到的异常。

改用这个模式:

using (SqlConnection conn  = new SqlConnection())
{
    conn.Open();
    Sqlmd.Connection = conn;
    SqlDataAdapter da = new SqlDataAdapter(Sqlmd);
   //...etc
}

换句话说,不要将连接定义为类的全局变量。

【讨论】:

  • “不要将连接定义为全局变量”:但是在我必须执行 sp 时如何避免创建和打开连接。在我的情况下,我必须执行很多 sp,并且没有实例化连接,另一种方法是每次都创建和打开。有什么提示吗?
【解决方案2】:

您所有的短暂 IDisposable 对象都缺少“使用”。那么,通过扩展,您可能已经做了类似的事情:

var reader = anotherCommand.ExecuteReader();
...

但这不会释放/关闭阅读器。如果是这种情况,请添加“使用”:

using(var reader = anotherCommand.ExecuteReader()) {
    ...
}

无论我们如何退出,它都会关闭阅读器。命令、连接、读取器和事务都是一次性的,通常都应该使用“使用”。

【讨论】:

    【解决方案3】:

    我建议您可以使用块来确保正确处理 sqlconnection。

    using (SqlConnection conn  = new SqlConnection())
    {
        conn.Open();
        Sqlmd.Connection = conn;
        SqlDataAdapter da = new SqlDataAdapter(Sqlmd);
        Dataset ds = new Datasest
        da.Fill(ds)
    }
    

    如果需要,您还可以在连接中设置 MARS 属性。

    SqlConnection m_ConStr;= new SqlConnection("Server= serverName;Database=yourDatabase;
            MultipleActiveResultSets=true;");
    

    【讨论】:

    • 连接应该在本地声明(如果使用共享实例会发生各种副作用)。另外,为什么不直接使用 using 语句来管理连接的生命周期?
    【解决方案4】:

    您正在尝试运行多个动作结果集(又名MARS)。

    想到了两种可能的解决方案:

    1. 在 GetContractResultSetByLead 中打开新连接
    2. 在您的数据库服务器上启用 MARS(如上述链接中所述)。

    【讨论】:

    • 您也可以尝试在web.config中将这个添加到连接字符串中:connectionString="MultipleActiveResultSets=True;user=..."
    猜你喜欢
    • 2011-08-29
    • 1970-01-01
    • 1970-01-01
    • 2017-07-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多