Errore “C’è già un DataReader aperto associato a questo comando che deve essere chiuso per primo” quando si usano 2 comandi distinti

Ho questo codice legacy:

private void conecta() { if (conexao.State == ConnectionState.Closed) conexao.Open(); } public List get_dados_historico_verificocoa_email_WEB(string email) { List historicos = new List(); conecta(); sql = @"SELECT * FROM historico_verificocoa_email WHERE nm_email = '" + email + @"' ORDER BY dt_verificocoa_email DESC, hr_verificocoa_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_verificocoa_email"].ToString(); dados_historico[1] = dados_historico[1].Substring(0, 10); dados_historico[2] = dr["hr_verificocoa_email"].ToString(); dados_historico[3] = dr["ds_tipo_verificocoa"].ToString(); sql = @"SELECT COUNT(e.cd_historico_verificocoa_email) QT FROM emails_lidos e WHERE e.cd_historico_verificocoa_email = '" + dr["cd_historico_verificocoa_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; } 

Ho creato due comandi separati per correggere il problema, ma continua ancora: “C’è già un DataReader aperto associato a questo comando che deve essere chiuso per primo”.

Altre informazioni: lo stesso codice funziona in un’altra app.

Suggerisco di creare una connessione aggiuntiva per il secondo comando, la risolveremo. Prova a combinare entrambe le query in una query. Creare una sottoquery per il conteggio.

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

Perché sovrascrivere lo stesso valore ancora e ancora?

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

Sarebbe abbastanza

Basta aggiungere quanto segue nella stringa di connessione:

 MultipleActiveResultSets=True; 
  1. La soluzione ottimale potrebbe essere quella di provare a trasformare la tua soluzione in un modulo in cui non è necessario avere due lettori aperti alla volta. Idealmente potrebbe essere una singola query. Non ho tempo di farlo ora.
  2. Se il tuo problema è così speciale che hai davvero bisogno di avere più lettori aperti contemporaneamente e che i tuoi requisiti non siano precedenti al back-end DB di SQL Server 2005, la parola magica è MARS (Multiple Active Result Sets) . http://msdn.microsoft.com/en-us/library/ms345109%28v=SQL.90%29.aspx . La soluzione dell’argomento collegato di Bob Vale mostra come abilitarlo: specifica MultipleActiveResultSets=true nella stringa di connessione. Dico solo una possibilità interessante, ma dovresti piuttosto trasformare la tua soluzione.

    • al fine di evitare la possibilità di iniezione SQL citata, impostare i parametri sullo SQLCommand stesso anziché incorporarli nella stringa di query. La stringa di query dovrebbe contenere solo i riferimenti ai parametri che vengono passati a SqlCommand.

È ansible ottenere un tale problema quando ci sono two different commands sulla stessa connessione, in particolare chiamando il secondo comando in un loop . Questo è il secondo comando per ogni record restituito dal primo comando. Se ci sono circa 10.000 record restituiti dal primo comando, questo problema sarà più probabile.

Ho evitato questo scenario rendendolo come un singolo comando. Il primo comando restituisce tutti i dati richiesti e li carica in un DataTable.

Nota: MARS può essere una soluzione, ma può essere rischiosa e molte persone non la amano.

Riferimento

  1. Cosa fa “Si è verificato un errore grave nel comando corrente. I risultati, se presenti, devono essere eliminati.” Errore di SQL Azure significa?
  2. Problemi da Linq-A-Sql e MARS – Si è verificato un grave errore nel comando corrente. I risultati, se presenti, dovrebbero essere scartati
  3. Complesso GROUP BY su DataTable

Scommetto che il problema viene mostrato in questa riga

 SqlDataReader dr3 = com2.ExecuteReader(); 

Suggerisco di eseguire il primo lettore e di fare un dr.Close(); e iterate historicos , con un altro ciclo, eseguendo com2.ExecuteReader() .

 public List get_dados_historico_verificocoa_email_WEB(string email) { List historicos = new List(); conecta(); sql = "SELECT * FROM historico_verificocoa_email WHERE nm_email = '" + email + "' ORDER BY dt_verificocoa_email DESC, hr_verificocoa_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_verificocoa_email"].ToString(); dados_historico[1] = dados_historico[1].Substring(0, 10); //System.Windows.Forms.MessageBox.Show(dados_historico[1]); dados_historico[2] = dr["hr_verificocoa_email"].ToString(); dados_historico[3] = dr["ds_tipo_verificocoa"].ToString(); dados_historico[5] = dr["cd_login_usuario"].ToString(); historicos.Add(dados_historico); } dr.Close(); sql = "SELECT COUNT(e.cd_historico_verificocoa_email) QT FROM emails_lidos e WHERE e.cd_historico_verificocoa_email = '" + dr["cd_historico_verificocoa_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; 

Prova a combinare la query, verrà eseguito molto più velocemente rispetto all’esecuzione di una query aggiuntiva per riga. A Ik non piace la stringa [] che stai usando, vorrei creare una class per contenere le informazioni.

  public List get_dados_historico_verificocoa_email_WEB(string email) { List historicos = new List(); using (SqlConnection conexao = new SqlConnection("ConnectionString")) { string sql = @"SELECT *, ( SELECT COUNT(e.cd_historico_verificocoa_email) FROM emails_lidos e WHERE e.cd_historico_verificocoa_email = a.nm_email ) QT FROM historico_verificocoa_email a WHERE nm_email = @email ORDER BY dt_verificocoa_email DESC, hr_verificocoa_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_verificocoa_email"].ToString(); dados_historico[1] = dados_historico[1].Substring(0, 10); //System.Windows.Forms.MessageBox.Show(dados_historico[1]); dados_historico[2] = dr["hr_verificocoa_email"].ToString(); dados_historico[3] = dr["ds_tipo_verificocoa"].ToString(); dados_historico[4] = dr["QT"].ToString(); dados_historico[5] = dr["cd_login_usuario"].ToString(); historicos.Add(dados_historico); } } } return historicos; } 

Non testato, ma maybee dà qualche idea.

Aggiungi MultipleActiveResultSets=true alla parte del provider della stringa di connessione. Vedi l’esempio qui sotto: