MySql.Data.MySqlClient.MySqlException: «Уже существует открытый DataReader, связанный с этим подключением, который должен быть закрыт первым».

0
MySqlCommand Sql1 = new MySqlCommand("SELECT * FROM animal WHERE idAnimal ='" + label1.Text + "'", Connection);

MySqlDataReader dr1;
dr1 = Sql1.ExecuteReader();

while (dr1.Read())
{
    String idAnimal = dr1["idAnimal"].ToString();

    MySqlCommand Sql2 = new MySqlCommand("SELECT * FROM town WHERE id ='" + idAnimal + "'", Connectio);
    MySqlDataReader dr2;
    dr2 = Sql2.ExecuteReader();

    while (dr2.Read())
    {
        dataGridView1.Rows.Add(dr2["number"], dr2["name"]);
    }

    dr2.Close();
}

dr1.Close();
Connection.Close();
  • 0
    Почему бы не сначала прочитать все значения idAnimal в массив, а затем закрыть первое устройство чтения? Кроме того, нет смысла «SELECT *», когда вы используете только одно поле ... и это поле является полем, которое вы передаете в качестве условия.
  • 2
    Г! Sql отверстие для инъекций, это жжет нас!
Теги:

3 ответа

2

Лучший способ решить это с помощью JOIN (и исправить это HUGE sql инъекционное отверстие, пока мы на нем):

string sql = "SELECT t.number, t.name FROM animal a INNER JOIN town t ON t.ID = a.idAnimal WHERE a.idAnimal= @idAnimal";

using (var cn = new MySqlConnection("connection string here"))
using (var cmd = new MySqlCommand(sql, cn))
{
    cmd.Parameters.Add("@idAnimal", MySqlDbType.Int32).Value = int.Parse(label1.Text);

    cn.Open();
    using (var dr = cmd.ExecuteReader())
    {
        while(dr.Read())
        {
            dataGridView1.Rows.Add(dr["number"], dr["name"]);
        }
        dr.Close();
    }
}

Кроме того, вы должны, вероятно, изучить привязку данных, чтобы связать эти результаты с сеткой, а не вручную добавлять строки. Это позволит вам написать такой код:

string sql = "SELECT t.number, t.name FROM animal a INNER JOIN town t ON t.ID = a.idAnimal WHERE a.idAnimal= @idAnimal";
using (var cn = new MySqlConnection("connection string here"))
using (var cmd = new MySqlCommand(sql, cn))
{
    cmd.Parameters.Add("@idAnimal", MySqlDbType.Int32).Value = int.Parse(label1.Text);
    cn.Open();
    using (var dr = cmd.ExecuteReader())
    {
        dataGridView1.DataSource = dr;
        dr.Close();
    }
}

Но если вы действительно хотите знать, как объединить два DataReaders, вы делаете это, имея два объекта соединения:

using (var cn1 = new MySqlConnection("connection string here"))
using (var sql1 = new MySqlCommand("SELECT * FROM animal WHERE idAnimal = @idAnimal", cn1))
{
    sql1.Parameters.Add("@idAnimal", MySqlDbType.Int32).Value = int.Parse(label1.Text);
    cn1.Open();
    using (var dr1 = sql1.ExecuteReader())
    {    
        while (dr1.Read())
        {
            String idAnimal = dr1["idAnimal"].ToString();

            using (var cn2 = new MySqlConnection("connection string here"))
            using (var sql2 = new MySqlCommand("SELECT * FROM town WHERE id = @idAnimal", cn2))
            {
                cn2.Parameters.Add("@idAnimal", MySqlDbType.Int32).Value = int.Parse(idAnimal);
                cn2.Open();
                using(var dr2 = sql2.ExecuteReader())
                {
                    while (dr2.Read())
                    {
                        dataGridView1.Rows.Add(dr2["number"], dr2["name"]);
                    }
                    dr2.Close();
                }
            }
        }
        dr1.Close();
    }
}

Но обратите внимание, что это более чем в два раза больше кода, чем опция JOIN + DataBinding.

Также обратите внимание, что это плохая практика в поставщиках ADO.Net сохранить одно соединения с базой данных для повторного использования в приложении. В дополнение к ограничению возможности одновременного использования нескольких запросов к базе данных, как мы видим здесь, ADO.Net использует функцию " Connection Pooling, и повторное использование того же объекта соединения мешает этому. В большинстве случаев лучше создать новый объект подключения и просто повторно использовать строку подключения.

  • 0
    Наконец-то понял! «Несколько запросов к базе данных одновременно». Поэтому не следует повторно использовать объект соединения, но, насколько я понимаю, соединение, как я понимаю, возвращает соединение в пул, как только оно закрывается. Как это мешает объединению?
  • 0
    Софт оф. Это действительно просто: не используйте один и тот же объект во всем приложении . Создать новые объекты не так сложно, и ADO.Net делает этот процесс быстрее для вашего приложения, чем повторное использование.
Показать ещё 6 комментариев
0

Вы не можете использовать одну и ту же переменную "Соединение" в двух командах одновременно. Просто нужно создать второй, если вы хотите открыть другое соединение внутри Read of the first.

0

Вы используете одно и то же соединение для DataReader и ExecuteNonQuery.which не поддерживается, в соответствии с MSDN. Вы должны создать сперва соединение для каждого datareader

  • 0
    Хотя это утверждение верно, если вы хотите сослаться на MSDN, вы должны предоставить ссылку на конкретную статью или ресурс.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню