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;
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.
È 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
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: