无法摆脱错误“已经有一个与此命令相关联的打开的数据读取器,必须先关闭”

本文关键字:读取 数据 关联 错误 命令 有一个 | 更新日期: 2023-09-27 18:01:55

我正在从同一数据库上的四个不同表中提取数据,并试图将这些数据合并到单个HTML对象中。问题是我一直得到上面的"open DataReader"异常。

我尝试过的事情:

  • 在每个if(reader.HasRows)块之后用reader.Close()关闭读取器
  • SqlCommandSqlDataReader局部向try/catch申报
  • 在每个关闭阅读器的try/catch的末尾添加一个finally语句(这一个抱怨reader变量没有被初始化)

以上都不起作用。我找到的所有解决方案都说使用MultipleActiveResultSets,但我实际上不想要多个结果集。

在这种情况下使用什么最佳实践?用四个不同的名字声明四个不同的读取器变量,reader1, reader2,等等?

编辑

这是我正在做的事情的精简版

string connectionString = ConfigurationManager.ConnectionStrings["database"].ToString();
DataTable dt = new DataTable();
SqlCommand cmd;
SqlDataReader reader;
SqlConnection conn;
using (conn = new SqlConnection(connectionString))
{
    try
    {
        conn.Open();
        cmd = new SqlCommand("SELECT * FROM [table-one]", conn);
        reader = cmd.ExecuteReader();
        if (reader.HasRows)
        {
            // Get a temporary copy of the data in a data table
            dt.Load(reader);
            // Do database things on table-one
        }
    }
    catch (Exception ex)
    {
        // Exception caught
        ThrowException(ex);
    }
    try
    {
        SqlCommand cmd = new SqlCommand("SELECT * FROM [table-two] WHERE UserID = @uID", conn);
        cmd.Parameters.Add(new SqlParameter("uID", User_ID));
        SqlDataReader reader = cmd.ExecuteReader();
        if (reader.HasRows)
        {
            // Get a temporary copy of the data in a data table
            dt.Load(reader);
            // Do database things on table-two
        }
    }
    catch (Exception ex)
    {
        // Exception caught
        ThrowException(ex);
    }

无法摆脱错误“已经有一个与此命令相关联的打开的数据读取器,必须先关闭”

而不是:

    cmd = new SqlCommand("SELECT * FROM [table-one]", conn);
    reader = cmd.ExecuteReader();
    if (reader.HasRows)
    {
        // Get a temporary copy of the data in a data table
        dt.Load(reader);
        // Do database things on table-one
    }

试题:

using (cmd = new SqlCommand("SELECT * FROM [table-one]", conn))
{
     using (reader = cmd.ExecuteReader())
     {
         if (reader.HasRows)
         {
             // Get a temporary copy of the data in a data table
             dt.Load(reader);
         }
     }
}
// Do database things on table-one

您需要为正在使用的每个命令/阅读器单独连接到数据库。请张贴有问题的代码,这将使它更容易给出一个更具体的答案。

如果要合并来自四个表的数据,为什么不在一个SQL语句中完成呢?您将只需要一个连接和一个命令。

虽然你说

我不想要多个结果集

运行四个单独的查询将得到四个单独的结果。

编辑

您已经在try/catch块之外声明了SQLSqlCommand,并且它似乎没有被关闭/清理。将声明移动到使用它的块中:

//SqlCommand cmd;       <<-- remove
//SqlDataReader reader; <<-- remove
SqlConnection conn;
using (conn = new SqlConnection(connectionString))
{
    try
    {
        conn.Open();
        // Add the variable declarations here
        SqlCommand cmd = new SqlCommand("SELECT * FROM [table-one]", conn);
        SqlDataReader reader = cmd.ExecuteReader();
        if (reader.HasRows)
        {
            // Get a temporary copy of the data in a data table
            dt.Load(reader);
            // Do database things on table-one
        }
    }
    catch (Exception ex)
    {
        // Exception caught
        ThrowException(ex);
    }
    ...

一般来说,这个错误有两个原因(至少到目前为止我还没有注意到其他原因):

第一个错误没有正确关闭Reader。使用:

可以很容易地解决这个问题
using (SqlConnection connection = new SqlConnection("connectionString"))
{
    using (SqlCommand command = connection.CreateCommand())
    {
        command.CommandText = "select getdate()";
        using (SqlDataReader reader = command.ExecuteReader())
        {
            while (reader.Read())
            {
                //do your stuff...
            }
        }
    }
}

第二个原因是并发性。如果您想从同一线程或另一个线程读取额外的数据,如以下所示:

using (SqlConnection connection = new SqlConnection("connectionString"))
{
    using (SqlCommand command = connection.CreateCommand())
    {
        command.CommandText = "select columns from accounts";
        using (SqlDataReader reader = command.ExecuteReader())
        {
            while (reader.Read())
            {
                //fetch additional data for each record.
                using (SqlCommand innerCommand = connection.CreateCommand())
                {
                    innerCommand.CommandText = "select * from sales where account_id = @account_id";
                    using (SqlDataReader innerReader = innerCommand.ExecuteReader())
                    {
                        while (innerReader.Read())
                        {
                            //read sales data    
                        }
                    }
                }
            }
        }
    }
}

您需要启用MultipleActiveResultSets。这样,SqlServer允许在一个连接上打开多个dataReader。从你的代码,似乎你遇到了第一个问题…

未关闭SqlDataReader。总是在完成读操作时调用Close,或者在Using语句中执行整个操作。

例子
DataTable dt = new DataTable();
//SqlCommand cmd;
//SqlDataReader reader;
//SqlConnection conn;
using (SqlConnection conn = new SqlConnection(connectionString))
{
    SqlCommand cmd;
    conn.Open();
    cmd = new SqlCommand("SELECT * FROM [table-one]", conn);
    using (SqlDataReader reader = cmd.ExecuteReader())
    {
        if (reader.HasRows)
        {
            // Get a temporary copy of the data in a data table
            dt.Load(reader);
            // Do database things on table-one
        }
    } 
    cmd = new SqlCommand("SELECT * FROM [table-two] WHERE UserID = @uID", conn);
    cmd.Parameters.Add(new SqlParameter("uID", User_ID));
    using (SqlDataReader reader = cmd.ExecuteReader())
    {
        if (reader.HasRows)
        {
            // Get a temporary copy of the data in a data table
            dt.Load(reader);
            // Do database things on table-two
        }
    }
}

在没有关闭第一个数据读取器对象的情况下调用第二个数据读取器。使用它来关闭属于您的相关数据读取器的相关事务

cmd = new SqlCommand("SELECT * FROM [table-one]", conn);
using (SqlDataReader reader = cmd.ExecuteReader())
{
    if (reader.HasRows)
    {
        // Get a temporary copy of the data in a data table
        dt.Load(reader);
        // Do database things on table-one
    }
    reader.Close();  
}