无法摆脱错误“已经有一个与此命令相关联的打开的数据读取器,必须先关闭”
本文关键字:读取 数据 关联 错误 命令 有一个 | 更新日期: 2023-09-27 18:01:55
我正在从同一数据库上的四个不同表中提取数据,并试图将这些数据合并到单个HTML对象中。问题是我一直得到上面的"open DataReader"异常。
我尝试过的事情:
- 在每个
if(reader.HasRows)
块之后用reader.Close()
关闭读取器 -
SqlCommand
和SqlDataReader
局部向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();
}