ASP.NET SqlDataReader抛出错误:读取器关闭时无效尝试调用Read

时间:2010-03-19 22:51:05

标签: c# ado.net

这个让我难过。以下是代码的相对位:

    public AgencyDetails(Guid AgencyId)
    {
        try
        {
            evgStoredProcedure Procedure = new evgStoredProcedure();
            Hashtable commandParameters = new Hashtable();
            commandParameters.Add("@AgencyId", AgencyId);
            SqlDataReader AppReader = Procedure.ExecuteReaderProcedure("evg_getAgencyDetails", commandParameters);
            commandParameters.Clear();

            //The following line is where the error is thrown. Errormessage: Invalid attempt to call Read when reader is closed.
            while (AppReader.Read())
            {
                AgencyName = AppReader.GetOrdinal("AgencyName").ToString();
                AgencyAddress = AppReader.GetOrdinal("AgencyAddress").ToString();
                AgencyCity = AppReader.GetOrdinal("AgencyCity").ToString();
                AgencyState = AppReader.GetOrdinal("AgencyState").ToString();
                AgencyZip = AppReader.GetOrdinal("AgencyZip").ToString();
                AgencyPhone = AppReader.GetOrdinal("AgencyPhone").ToString();
                AgencyFax = AppReader.GetOrdinal("AgencyFax").ToString();
            }
            AppReader.Close();
            AppReader.Dispose();
        }
        catch (Exception ex)
        {
            throw new Exception("AgencyDetails Constructor: " + ex.Message.ToString());
        }
    }

执行ExecuteReaderProcedure:

    public SqlDataReader ExecuteReaderProcedure(string ProcedureName, Hashtable Parameters)
    {
        SqlDataReader returnReader;

        using (SqlConnection conn = new SqlConnection(connectionString))
        {
            try
            {
                SqlCommand cmd = new SqlCommand(ProcedureName, conn);
                SqlParameter param = new SqlParameter();
                cmd.CommandType = System.Data.CommandType.StoredProcedure;

                foreach (DictionaryEntry keyValue in Parameters)
                {
                    cmd.Parameters.AddWithValue(keyValue.Key.ToString(), keyValue.Value);
                }

                conn.Open();
                returnReader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
            }
            catch (SqlException e)
            {
                throw new Exception(e.Message.ToString());
            }
        }
        return returnReader;
    }

连接字符串正在运行,因为同一个类中的其他存储过程运行正常。唯一的问题似乎是从这个方法返回SqlDataReaders!他们在标题中抛出错误消息。任何想法都非常感谢!提前谢谢!

1 个答案:

答案 0 :(得分:5)

DataReader通常直接连接到数据库。在这种情况下,当您从方法返回时,您将从创建using对象的SqlConnetion语句内部返回。这会在Dispose上调用SqlConnection,并使SqlDataReader无用。

试试这个:

public SqlDataReader ExecuteReaderProcedure(string ProcedureName, Hashtable Parameters)
{
    SqlConnection conn = new SqlConnection(connectionString);
    using(SqlCommand cmd = new SqlCommand(ProcedureName, conn))
    {
        cmd.CommandType = System.Data.CommandType.StoredProcedure;

        foreach(DictionaryEntry keyValue in Parameters)
        {
            cmd.Parameters.AddWithValue(keyValue.Key.ToString(), keyValue.Value);
        }

        conn.Open();
        return cmd.ExecuteReader(CommandBehavior.CloseConnection);
    }
}

这样称呼:

public AgencyDetails(Guid AgencyId)
{
    evgStoredProcedure Procedure = new evgStoredProcedure();
    Hashtable commandParameters = new Hashtable();
    commandParameters.Add("@AgencyId", AgencyId);
    using(SqlDataReader AppReader = 
        Procedure.ExecuteReaderProcedure("evg_getAgencyDetails", 
                                         commandParameters))
    {
        commandParameters.Clear();

        while(AppReader.Read())
        {
            AgencyName = AppReader.GetOrdinal("AgencyName").ToString();
            AgencyAddress = AppReader.GetOrdinal("AgencyAddress").ToString();
            AgencyCity = AppReader.GetOrdinal("AgencyCity").ToString();
            AgencyState = AppReader.GetOrdinal("AgencyState").ToString();
            AgencyZip = AppReader.GetOrdinal("AgencyZip").ToString();
            AgencyPhone = AppReader.GetOrdinal("AgencyPhone").ToString();
            AgencyFax = AppReader.GetOrdinal("AgencyFax").ToString();
        }
    }
}

using的{​​{1}}语句末尾,将调用AppReader。由于您使用AppReader.Dispose来呼叫ExecuteReader,因此处理读取器也会关闭连接。

请注意,我也摆脱了您的错误异常处理。除了可能向最终用户显示外,切勿使用CommandBehavior.CloseConnection。其他人都想要完整的例外。此外,如果允许传播完整的异常,则无需将方法名称作为异常消息的一部分进行打印。方法名称将位于堆栈跟踪中。