0

我有一个通用方法来调用 ASP.NET 中的存储过程:

public SqlDataReader ExecuteStoredProc(string sprocName, SqlParameter[] SqlP)
        {
            SqlDataReader iReader;
            SqlCommand sql = new SqlCommand();

            sql.CommandText = sprocName;
            sql.CommandType = CommandType.StoredProcedure;
            sql.Connection = ConnStr;
            if (SqlP != null)
            {
                foreach (SqlParameter p in SqlP)
                {
                    sql.Parameters.Add(p);
                }

            }
            sql.Connection.Open();
            iReader = sql.ExecuteReader(CommandBehavior.CloseConnection);
            sql.Dispose();

            return iReader;
        }

即使我正在调用 CommandBehavior.CloseConnection,连接也没有关闭。第一次请求页面时,我可以很好地获取数据。重新加载时出现以下错误:

连接未关闭。连接的当前状态是打开的。说明:执行当前 Web 请求期间发生未处理的异常。请查看堆栈跟踪以获取有关错误及其源自代码的位置的更多信息。

异常详细信息:System.InvalidOperationException:连接未关闭。连接的当前状态是打开的。

源错误:

第 35 行:第 36 行:} 第 37 行:sql.Connection.Open(); 第 38 行:iReader = sql.ExecuteReader(CommandBehavior.CloseConnection); 第 39 行:sql.Dispose();

最后,如果我把 sql.Connection.Close(); 之前 sql.Dispose(); 我收到 iReader 不可读的错误,因为它已经关闭。

显然我错误地关闭了我的连接,有人能指出我正确的方向吗?

4

4 回答 4

4

返回 DataReader 时,基础连接必须保持打开状态。正确清理资源是消费者的责任。

public SqlDataReader ExecuteStoredProc(string sprocName, SqlParameter[] SqlP)
{
    SqlCommand sql = new SqlCommand();

    sql.CommandText = sprocName;
    sql.CommandType = CommandType.StoredProcedure;
    sql.Connection = ConnStr;
    if (SqlP != null)
    {
        foreach (SqlParameter p in SqlP)
        {
            sql.Parameters.Add(p);
        }

    }
    sql.Connection.Open();
    return sql.ExecuteReader(CommandBehavior.CloseConnection);          
}

public void ConsumingMethod()
{
    using(SqlDataReader reader = ExecuteStoredProc("MyProc", params))
    {
        while(reader.Read())
        {
            //work with your reader
        }
    }
}
于 2009-06-03T20:13:06.293 回答
1

我建议用“使用”语句包装 sql 连接,这将解决大多数 sql 连接问题。

using (var conn = new SqlConnection("..."))
{
    conn.Open();
    using (var cmd = conn.CreateCommand())
    {
        cmd.CommandText = "...";
        using (var reader = cmd.ExecuteReader())
        {
            while (reader.Read())
            {
                // ...
            }
        }
    }

}

于 2009-06-03T20:11:54.907 回答
0

这个想法是做一个 Connection.Close(); 在你完成 SqlReader 之后,所以基本上不要将 close() 语句放在 SqlReader.Dispose() 命令之前,而应该将它放在下面。

于 2009-06-03T20:28:03.687 回答
0

这是我处理 IDataReader 的首选方式。让调用者创建 SqlConnection 实例并传递给方法。

创建 SqlConnection 实例的成本很高。你最终会在不同的情况下多次调用相同的 ExecuteStoredProc 方法。

因此,我通过添加 SqlConnection 实例作为参数的一部分来重构 ExecuteStoredProc 方法。

using (SqlConnection conn = new SqlConnection())
{
    conn.ConnectionString = // Connection String;
    conn.Open();

    using (IDataReader reader = foo.ExecuteStoredProc(conn, sprocName, SqlP))
    {
        // Process IDataReader
    }
}
于 2009-06-03T21:00:11.643 回答