Ich habe diesen Legacy-Code:
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;
}
Ich habe zwei separate Befehle erstellt, um das Problem zu beheben, aber es wird weiterhin fortgesetzt: "Diesem Befehl ist bereits ein offener DataReader zugeordnet, der zuerst geschlossen werden muss."
Eine zusätzliche Info: Der gleiche Code funktioniert in einer anderen App.
Antworten:
Ich schlage vor, eine zusätzliche Verbindung für den zweiten Befehl zu erstellen, würde es lösen. Versuchen Sie, beide Abfragen in einer Abfrage zu kombinieren. Erstellen Sie eine Unterabfrage für die Zählung.
while (dr3.Read()) { dados_historico[4] = dr3["QT"].ToString(); //quantidade de emails lidos naquela verificação }
Warum immer wieder denselben Wert überschreiben?
if (dr3.Read()) { dados_historico[4] = dr3["QT"].ToString(); //quantidade de emails lidos naquela verificação }
Wäre genug.
quelle
Fügen Sie einfach Folgendes in Ihre Verbindungszeichenfolge ein:
quelle
Wenn Ihr Problem so speziell ist, dass wirklich mehr Leser gleichzeitig geöffnet sein müssen und Ihre Anforderungen nicht älter als das SQL Server 2005 DB-Backend sind, lautet das Zauberwort MARS (Multiple Active Result Sets) . http://msdn.microsoft.com/en-us/library/ms345109%28v=SQL.90%29.aspx . Die Lösung des verknüpften Themas von Bob Vale zeigt, wie es aktiviert wird: Geben Sie
MultipleActiveResultSets=true
in Ihrer Verbindungszeichenfolge an. Ich sage dies nur als interessante Möglichkeit, aber Sie sollten Ihre Lösung lieber umwandeln.quelle
Sie können ein solches Problem bekommen, wenn Sie sich
two different commands
in derselben Verbindung befinden - insbesondere wenn Sie den zweiten Befehl in a aufrufenloop
. Das heißt, der zweite Befehl wird für jeden Datensatz aufgerufen, der vom ersten Befehl zurückgegeben wird. Wenn vom ersten Befehl etwa 10.000 Datensätze zurückgegeben werden, ist dieses Problem wahrscheinlicher.Früher habe ich ein solches Szenario vermieden, indem ich es als einzelnen Befehl erstellt habe. Der erste Befehl gibt alle erforderlichen Daten zurück und lädt sie in eine DataTable.
Hinweis:
MARS
Kann eine Lösung sein - aber es kann riskant sein und viele Leute mögen es nicht.Referenz
quelle
Ich wette, das Problem wird in dieser Zeile angezeigt
Ich schlage vor, dass Sie den ersten Leser ausführen und a
dr.Close();
und iterierenhistoricos
mit einer anderen Schleife ausführencom2.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;
quelle
Versuchen Sie, die Abfrage zu kombinieren. Sie wird viel schneller ausgeführt als die Ausführung einer zusätzlichen Abfrage pro Zeile. Ich mag die Zeichenfolge [], die Sie verwenden, nicht. Ich würde eine Klasse zum Speichern der Informationen erstellen.
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; }
Ungetestet, aber vielleicht gibt eine Idee.
quelle
Fügen Sie
MultipleActiveResultSets=true
dem Provider einen Teil Ihrer Verbindungszeichenfolge hinzu. Siehe das folgende Beispiel:<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" />
quelle