错误“已经有一个与此命令相关联的打开的 DataReader,必须首先关闭”,当使用2个不同的命令时

我有个遗产代码:

 private void conecta()
{
if (conexao.State == ConnectionState.Closed)
conexao.Open();
}


public List<string[]> get_dados_historico_verificacao_email_WEB(string email)
{
List<string[]> historicos = new List<string[]>();
conecta();


sql =
@"SELECT *
FROM historico_verificacao_email
WHERE nm_email = '" + email + @"'
ORDER BY dt_verificacao_email DESC, hr_verificacao_email DESC";


com = new SqlCommand(sql, conexao);
SqlDataReader dr = com.ExecuteReader();


if (dr.HasRows)
{
while (dr.Read())
{
string[] dados_historico = new string[6];
dados_historico[0] = dr["nm_email"].ToString();
dados_historico[1] = dr["dt_verificacao_email"].ToString();
dados_historico[1] = dados_historico[1].Substring(0, 10);
dados_historico[2] = dr["hr_verificacao_email"].ToString();
dados_historico[3] = dr["ds_tipo_verificacao"].ToString();


sql =
@"SELECT COUNT(e.cd_historico_verificacao_email) QT
FROM emails_lidos e
WHERE e.cd_historico_verificacao_email =
'" + dr["cd_historico_verificacao_email"].ToString() + "'";


tipo_sql = "seleção";
conecta();
com2 = new SqlCommand(sql, conexao);


SqlDataReader dr3 = com2.ExecuteReader();
while (dr3.Read())
{
//quantidade de emails lidos naquela verificação
dados_historico[4] = dr3["QT"].ToString();
}
dr3.Close();
conexao.Close();


//login
dados_historico[5] = dr["cd_login_usuario"].ToString();
historicos.Add(dados_historico);
}
dr.Close();
}
else
{
dr.Close();
}


conexao.Close();
return historicos;
}


我已经创建了两个单独的命令来纠正这个问题,但它仍然继续说: “已经有一个与此命令相关联的打开的 DataReader,必须首先关闭”。

附加信息: 同样的代码在另一个应用程序中工作。

220437 次浏览

我建议为第二个命令创建一个额外的连接,就可以解决这个问题。尝试将两个查询组合在一个查询中。为计数创建子查询。

while (dr3.Read())
{
dados_historico[4] = dr3["QT"].ToString(); //quantidade de emails lidos naquela verificação
}

为什么要一次又一次地重写相同的值?

if (dr3.Read())
{
dados_historico[4] = dr3["QT"].ToString(); //quantidade de emails lidos naquela verificação
}

就够了。

我打赌问题就在这条线上

SqlDataReader dr3 = com2.ExecuteReader();

我建议您执行第一个读取器,执行 dr.Close();和迭代 historicos,并使用另一个循环执行 com2.ExecuteReader()

public List<string[]> get_dados_historico_verificacao_email_WEB(string email)
{


List<string[]> historicos = new List<string[]>();
conecta();
sql = "SELECT * FROM historico_verificacao_email WHERE nm_email = '" + email + "' ORDER BY  dt_verificacao_email DESC, hr_verificacao_email DESC";
com = new SqlCommand(sql, conexao);
SqlDataReader dr = com.ExecuteReader();


if (dr.HasRows)
{
while (dr.Read())
{
string[] dados_historico = new string[6];
dados_historico[0] = dr["nm_email"].ToString();
dados_historico[1] = dr["dt_verificacao_email"].ToString();
dados_historico[1] = dados_historico[1].Substring(0, 10);
//System.Windows.Forms.MessageBox.Show(dados_historico[1]);
dados_historico[2] = dr["hr_verificacao_email"].ToString();
dados_historico[3] = dr["ds_tipo_verificacao"].ToString();
dados_historico[5] = dr["cd_login_usuario"].ToString();
historicos.Add(dados_historico);
}


dr.Close();


sql = "SELECT COUNT(e.cd_historico_verificacao_email) QT FROM emails_lidos e WHERE e.cd_historico_verificacao_email = '" + dr["cd_historico_verificacao_email"].ToString() + "'";
tipo_sql = "seleção";
com2 = new SqlCommand(sql, conexao);


for(int i = 0 ; i < historicos.Count() ; i++)
{
SqlDataReader dr3 = com2.ExecuteReader();
while (dr3.Read())
{
historicos[i][4] = dr3["QT"].ToString(); //quantidade de emails lidos naquela verificação
}
dr3.Close();
}


}


return historicos;
  1. 最佳的解决方案可能是尝试将 改变你的解决方案转换成不需要同时打开两个读取器的形式。理想情况下,它可以是单个查询。我现在没时间。
  2. 如果您的问题非常特殊,以至于您确实需要同时打开更多的读取器,并且您的要求允许不超过 SQL Server 2005 DB 后端,那么关键词就是 多个活动结果集http://msdn.microsoft.com/en-us/library/ms345109%28v=SQL.90%29.aspx.Bob Vale 的链接主题解决方案显示了如何启用它: 在连接字符串中指定 MultipleActiveResultSets=true。我只是说这是一种有趣的可能性,但你应该转换你的解决方案。

    • 为了避免上面提到的 SQL 注入的可能性,将参数设置为 SQLCommand 本身,而不是将它们嵌入到查询字符串中。查询字符串应该只包含对传递给 SqlCommand 的参数的引用。

尝试组合查询,它将比每行执行一个额外的查询快得多。 我不喜欢你使用的字符串[] ,我会创建一个类来保存信息。

    public List<string[]> get_dados_historico_verificacao_email_WEB(string email)
{
List<string[]> historicos = new List<string[]>();


using (SqlConnection conexao = new SqlConnection("ConnectionString"))
{
string sql =
@"SELECT    *,
(   SELECT      COUNT(e.cd_historico_verificacao_email)
FROM        emails_lidos e
WHERE       e.cd_historico_verificacao_email = a.nm_email ) QT
FROM      historico_verificacao_email a
WHERE     nm_email = @email
ORDER BY  dt_verificacao_email DESC,
hr_verificacao_email DESC";


using (SqlCommand com = new SqlCommand(sql, conexao))
{
com.Parameters.Add("email", SqlDbType.VarChar).Value = email;


SqlDataReader dr = com.ExecuteReader();


while (dr.Read())
{
string[] dados_historico = new string[6];
dados_historico[0] = dr["nm_email"].ToString();
dados_historico[1] = dr["dt_verificacao_email"].ToString();
dados_historico[1] = dados_historico[1].Substring(0, 10);
//System.Windows.Forms.MessageBox.Show(dados_historico[1]);
dados_historico[2] = dr["hr_verificacao_email"].ToString();
dados_historico[3] = dr["ds_tipo_verificacao"].ToString();
dados_historico[4] = dr["QT"].ToString();
dados_historico[5] = dr["cd_login_usuario"].ToString();


historicos.Add(dados_historico);
}
}
}
return historicos;
}

没有经过测试,但也许 Bee 能提供一些线索。

当您在同一个连接上是 two different commands时,您可能会遇到这样的问题-特别是调用 loop中的第二个命令。它为从第一个命令返回的每个记录调用第二个命令。如果第一个命令返回大约10,000条记录,则更有可能出现这个问题。

I used to avoid such a scenario by making it as a single command.. The first command returns all the required data and load it into a DataTable.

注意: MARS可能是一个解决方案-但它可能是危险的,许多人不喜欢它。

参考文献

  1. 什么是“当前命令发生严重错误。如果有的话,结果应该被抛弃。”SQL Azure 错误是什么意思?
  2. Linq-To-Sql 和 MARS 问题-当前命令出现严重错误。如果有结果,应该丢弃
  3. 数据表上的复杂 GROUPBY

只需在连接字符串中添加以下内容:

MultipleActiveResultSets=True;

MultipleActiveResultSets=true添加到连接字符串的提供程序部分:

<add name="DbContext" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=dbName;Persist Security Info=True;User ID=userName;Password=password;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" />