2017-02-22 1 views
1

Так что это немного похоже на код.Закрытие соединения datareader для подключения к MySql

У меня есть функция, которая проверяет последний идентификатор в таблице, эта функция вызывается внутри другой функции. В конце этой функции у меня есть другая функция, открывающая другой datareader.

Ошибка:

There is already an open Datareader associated with this connection which must be closed first.

getLastIdfromDB()

public string getLastIdFromDB() 
{ 
    int lastIndex; 
    string lastID =""; 
    var dbCon = DB_connect.Instance(); 

    if (dbCon.IsConnect()) 
    { 
     MySqlCommand cmd2 = new MySqlCommand("SELECT ID FROM `competitor`", dbCon.Connection); 

     try 
     { 
      MySqlDataReader reader = cmd2.ExecuteReader(); 

      while (reader.Read()) 
      { 
        string item = reader2["ID"].ToString(); 
        lastIndex = int.Parse(item); 
        lastIndex++; 
        lastID = lastIndex.ToString(); 
       } 
     } 
     catch (Exception ex) 
     { 
       MessageBox.Show("Error:" + ex.Message); 
     } 
    } 

    return lastID; 
} 

Эта функция позже на используемый в этой функции:

private void addPlayerBtn_Click(object sender, EventArgs e) 
{ 
    ListViewItem lvi = new ListViewItem(getLastIdFromDB()); 
    .........................................^ 
    ...         HERE 
    ... 
    ... irrelevant code removed 
    ......................................... 

      var dbCon = DB_connect.Instance(); 

      if (dbCon.IsConnect()) 
      { 
       MySqlCommand cmd = new MySqlCommand("INSERT INTO `competitor`(`ID`, `Name`, `Age`) VALUES(@idSql,@NameSql,@AgeSql)", dbCon.Connection); 
       cmd.Parameters.AddWithValue("@idSql", getLastIdFromDB()); 
       cmd.Parameters.AddWithValue("@NameSql", playerName.Text); 
       cmd.Parameters.AddWithValue("@AgeSql", playerAge.Text); 

       try 
       { 
        cmd.ExecuteNonQuery(); 
        listView1.Items.Clear(); 
       } 
       catch (Exception ex) 
       { 
        MessageBox.Show("Error:" + ex.Message); 
        dbCon.Connection.Close(); 
       } 
       finally 
       { 
        updateListView(); 
       } 
     } 
} 

Что бы быть лучшим способом для мне решить эту проблему и в будущем обязательно закрыть m y соединений правильно?

UPDATE: (по запросу, включены DB_connect)

class DB_connect 
    { 
     private DB_connect() 
     { 
     } 

     private string databaseName = "simhopp"; 

     public string DatabaseName 
     { 
      get { return databaseName; } 
      set { databaseName = value; } 
     } 

     public string Password { get; set; } 
     private MySqlConnection connection = null; 

     public MySqlConnection Connection 
     { 
      get { return connection; } 
     } 

     private static DB_connect _instance = null; 

     public static DB_connect Instance() 
     { 
      if (_instance == null) 
       _instance = new DB_connect(); 
      return _instance; 
     } 

     public bool IsConnect() 
     { 
      bool result = true; 

      try 
      { 
       if (Connection == null) 
       { 
        if (String.IsNullOrEmpty(databaseName)) 
         result = false; 

        string connstring = string.Format("Server=localhost; database={0}; UID=root;", databaseName); 

        connection = new MySqlConnection(connstring); 
        connection.Open(); 

        result = true; 
       } 
      } 
      catch (Exception ex) 
      { 
       Console.Write("Error: " + ex.Message); 
      } 

      return result; 
     } 

     public void Close() 
     { 
      connection.Close(); 
     } 
    } 
} 
+0

'DB_connect' - что это? – mason

+0

@mason просто функция, которая следит за тем, чтобы я был связан с DB – Joel

+0

. Сначала я бы включил 'MySqlDataReader reader' в блок' Using' – Pikoh

ответ

0

Как было предложено Pikoh в комментариях, использование предложения using действительно решило его для меня.

Рабочий код-фрагмент:

getLastIdFromDB

using (MySqlDataReader reader2 = cmd2.ExecuteReader()) { 

     while (reader2.Read()) 
     { 
     string item = reader2["ID"].ToString(); 
     lastIndex = int.Parse(item); 
     lastIndex++; 
     lastID = lastIndex.ToString(); 
     } 
} 
+0

Кроме того, это не связано с этой проблемой, но я бы предложил более эффективный способ получить следующий id из db. Извлечение всех строк из этой таблицы и установка одинакового значения в цикле while кажутся довольно неэффективными. Если вы не можете использовать автоинкрементный столбец, можно ли использовать MAX (ID)? Таким образом, вы можете использовать 'if' вместо' while'. – sudheeshix

+0

извините, это был единственный метод, который на самом деле дал мне последнюю ID-запись в db. Я попытался использовать MAX, но mySQL в C# мне не понравился, всегда дал мне -1 взамен (я попробовал несколько решений, поэтому я вернулся к этому базовому решению) – Joel

2

Вы пытаетесь иметь несколько открытых читателей на том же соединении. Обычно это называется «MARS» (несколько активных наборов результатов). MySql, похоже, не поддерживает его.

Вам придется либо ограничиться одним открытым читателем за один раз, либо использовать более одного соединения, чтобы вы могли иметь одно соединение для каждого читателя.

Мое предложение было бы выбрасывать эту однополюсную вещь и вместо этого использовать connection pooling и соответствующие using блоки.

0

Ваша обработка здесь соединение не хорошо. Вам нужно выровнять DB_connect. Нет необходимости поддерживать одно соединение - просто открывайте и закрывайте соединение каждый раз, когда вам это нужно. Под обложками ADO.NET «объединит» соединение для вас, так что вам не придется ждать, чтобы снова подключиться.

Для любого объекта, который реализует IDisposable вам необходимо либо позвонить .Dispose() на него в finally блоке, или обернуть его в using заявлении. Это гарантирует, что ваши ресурсы будут утилизированы надлежащим образом. Я рекомендую оператор using, потому что он помогает держать область видимой.

Ваши соглашения об именах должны соответствовать стандартам C#. Методы, возвращающие логическое значение, должны быть равны IsConnected, а не IsConnect. addPlayerBtn_Click должно быть AddPlayerButton_Click. getLastIdFromDB должно быть GetlastIdFromDb или getLastIdFromDatabase.

public string GetLastIdFromDatabase() 
{ 
    int lastIndex; 
    string lastID =""; 

    using (var connection = new MySqlConnection(Configuration.ConnectionString)) 
    using (var command = new MySqlCommand("query", connection)) 
    { 
     connection.Open(); 
     MySqlDataReader reader = cmd2.ExecuteReader(); 

     while (reader.Read()) 
     { 
       string item = reader2["ID"].ToString(); 
       lastIndex = int.Parse(item); 
       lastIndex++; 
       lastID = lastIndex.ToString(); 
     } 
    } 

    return lastID; 
} 

Обратите внимание, что ваш запрос тоже плох.Я подозреваю, что вы используете строковый тип данных вместо числа, хотя ваши идентификаторы основаны на цифрах. Вы должны переключить столбец на тип данных, а затем выбрать номер max(). Или используйте автоинкрементный столбец или последовательность, чтобы получить следующий идентификатор. Чтение каждой отдельной строки для определения следующего идентификатора и приращения счетчика не очень хорошо.

+0

Благодарим вас за отзыв. Соглашения об именах, первая буква самозаверяемых функций или переменных начинается с строчных букв, чтобы отличать их от встроенных функций. Тем не менее, функции Bool я использую имена верхнего регистра. Во-вторых. Я пробовал запрос max(), а также TOP 1, но оба дали мне -1 в качестве вывода. это было единственное, что действительно дало мне правильный запрос-ответ. Я также использую, наконец, блоки блоков, но я удалил их из этого вопроса, чтобы уменьшить количество кода. – Joel

Смежные вопросы