Обновление базы данных никогда не работает с первого раза, нужно делать это дважды?

#c# #mysql #datagridview #sql-update #sql-insert

Вопрос:

Я пытаюсь обновить/отредактировать базу данных, используя представление DataGrid, которое пользователь может редактировать/вставлять строки/удалять строки. Похоже, все работает до нажатия на ячейки ссылки «Вставить» или «Обновить». Они всегда выходят из строя при первом щелчке (это не дает подробной ошибки) и всегда срабатывают при втором щелчке.

Я не вижу, что меняется между щелчками один или два раза.

ЗАГРУЗКА ДАННЫХ В ПРЕДСТАВЛЕНИЕ DATAGRIDVIEW:

 private void loadDB()
        {
            try
            {
                string connstring = string.Format("Server={0}; database={1}; UID={2}; password={3}",
                dbUtil.creds.server, dbUtil.creds.database, dbUtil.creds.username, dbUtil.creds.password);

                conn = new MySqlConnection(connstring);

                // since we have multiple tables we cant load data on form load
                // so we cant open conn there either. do it here, only once, the first time.
                onlyOnce();

                adapter = new MySqlDataAdapter("SELECT *, 'Delete' AS 'Delete' FROM RIS"   tableShown, conn);
                builder = new MySqlCommandBuilder(adapter);

                adapter.InsertCommand = builder.GetInsertCommand();
                adapter.UpdateCommand = builder.GetUpdateCommand();
                adapter.DeleteCommand = builder.GetDeleteCommand();

                ds = new DataSet();
                adapter.Fill(ds, "RIS"   tableShown);
                dbView.DataSource = null;
                dbView.DataSource = ds.Tables["RIS"   tableShown];

                for (int i = 0; i < dbView.Rows.Count; i  )
                {
                    DataGridViewLinkCell linkCell = new DataGridViewLinkCell();
                    dbView[dbView.Columns.Count - 1, i] = linkCell;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            cellCount = dbView.Columns.Count - 1;
        }
 

ОБНОВИТЕ ЯЧЕЙКУ, ЕСЛИ ПОЛЬЗОВАТЕЛЬ ДОБАВИЛ СТРОКУ:

         private void dbView_UserAddedRow(object sender, DataGridViewRowEventArgs e)
        {
            int lastRow = dbView.Rows.Count - 2;
            DataGridViewRow nRow = dbView.Rows[lastRow];
            DataGridViewLinkCell linkCell = new DataGridViewLinkCell();
            dbView[cellCount, lastRow] = linkCell;
            nRow.Cells["Delete"].Value = "Insert";
        }
 

ОБНОВИТЕ ЯЧЕЙКУ, ЕСЛИ ПОЛЬЗОВАТЕЛЬ ИЗМЕНИЛ ЯЧЕЙКУ В СУЩЕСТВУЮЩЕЙ СТРОКЕ:

         private void dbView_CellEndEdit(object sender, DataGridViewCellEventArgs e)
        {
            try
            {
                int lastRow = e.RowIndex;
                DataGridViewRow nRow = dbView.Rows[lastRow];
                DataGridViewLinkCell linkCell = new DataGridViewLinkCell();
                dbView[cellCount, lastRow] = linkCell;
                if (dbView.Rows[e.RowIndex].Cells[cellCount].Value.ToString() == "Delete")
                {
                    nRow.Cells["Delete"].Value = "Update";
                }
            }
            catch (Exception ex) { MessageBox.Show(ex.Message); }
        }
 

В ЗАВИСИМОСТИ ОТ ЗНАЧЕНИЯ ЯЧЕЙКИ ОБНОВИТЕ / ВСТАВЬТЕ / ИЛИ УДАЛИТЕ СТРОКУ:

  private void dbView_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            string database = "RIS"   tableShown;
            int result = 0;
            try
            {
                if (e.ColumnIndex == cellCount)
                {
                    string Task = dbView.Rows[e.RowIndex].Cells[cellCount].Value.ToString();
                    if (Task == "Delete")
                    {
                        if (MessageBox.Show("Are you sure to delete?", "Deleting...", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                        {
                            int ThisRow = e.RowIndex;
                            dbView.Rows.RemoveAt(ThisRow);
                            ds.Tables[database].Rows[ThisRow].Delete();
                            result = adapter.Update(ds, database);
                        }
                    }
                    else if (Task == "Insert")
                    {
                        int lastRow = dbView.Rows.Count - 2;
                        DataRow dr = ds.Tables[database].NewRow();
                        foreach (DataGridViewColumn col in dbView.Columns)
                        {
                            if (col.HeaderText != "Delete")
                            {
                                dr[col.HeaderText] = dbView.Rows[lastRow].Cells[col.HeaderText].Value;
                            }
                        }
                        ds.Tables[database].Rows.Add(dr);
                        ds.Tables[database].Rows.RemoveAt(ds.Tables[database].Rows.Count - 1);
                        dbView.Rows.RemoveAt(dbView.Rows.Count - 2);
                        dbView.Rows[e.RowIndex].Cells[cellCount].Value = "Delete";
                        result = adapter.Update(ds, database);
                    }
                    else if (Task == "Update")
                    {
                        int thisRow = e.RowIndex;
                        foreach (DataGridViewColumn col in dbView.Columns)
                        {
                            if (col.HeaderText != "Delete")
                            {
                                ds.Tables[database].Rows[thisRow][col.HeaderText] = dbView.Rows[thisRow].Cells[col.HeaderText].Value;
                            }
                        }
                        result = adapter.Update(ds, database);
                        dbView.Rows[e.RowIndex].Cells[cellCount].Value = "Delete";
                    }
                }
            }
            catch (Exception ex) { }
            // reload data to clear ds and dt after success
            if(result > 0)
            {
                loadDB();
            }
        }
 

Есть идеи, почему при первом нажатии на ссылку происходит сбой, но не во второй раз?

Комментарии:

1. что вы подразумеваете под неудачей в первый раз? Есть ли какое-нибудь исключение?

2. Удалось получить более подробное исключение: [не удается записать данные в транспортное соединение. Существующее соединение было принудительно закрыто удаленным хостом.]

3. Пробовали установить ОБЪЕДИНЕНИЕ в ложь и истину, ни то, ни другое не имеет значения.

4. Я понятия не имею, почему ты беспокоишься обо всем этом. Объект данных уже отслеживает изменения, внесенные в его строки в режиме добавления/обновления/удаления. Вы напрасно изобретаете здесь колесо

5. Нет, набор данных отслеживает изменения, которые затем должны быть обновлены на удаленном сервере MySQL. Именно это и происходит…

Ответ №1:

Для тех, кто может столкнуться с подобной ошибкой, вот более элегантный способ сделать это (без ошибок).

         private void loadDB()
        {
            
                string connstring = string.Format("Server={0}; database={1}; UID={2}; password={3};",
                dbUtil.creds.server, dbUtil.creds.database, dbUtil.creds.username, dbUtil.creds.password);

                conn = new MySqlConnection(connstring);

            if (this.OpenConnection() == true)
            {
                adapter = new MySqlDataAdapter("select * from RIS"   tableShown, conn);
                DataSet DS = new DataSet();
                adapter.Fill(DS);
                dbView.DataSource = DS.Tables[0];

                //close connection
                this.CloseConnection();
            }
        }

        private bool OpenConnection()
        {
            try
            {
                conn.Open();
                return true;
            }
            catch (MySqlException ex)
            {
                //When handling errors, you can your application's response based on the error number.
                //The two most common error numbers when connecting are as follows:
                //0: Cannot connect to server.
                //1045: Invalid user name and/or password.
                switch (ex.Number)
                {
                    case 0:
                        MessageBox.Show("Cannot connect to server. Contact administrator");
                        break;
                    case 1045:
                        MessageBox.Show("Invalid username/password, please try again");
                        break;
                    default:
                        MessageBox.Show(ex.Message);
                        break;
                }
                return false;
            }
        }

        private bool CloseConnection()
        {
            try
            {
                conn.Close();
                return true;
            }
            catch (MySqlException ex)
            {
                MessageBox.Show(ex.Message);
                return false;
            }
        }

        private void dbView_RowValidated(object sender, DataGridViewCellEventArgs e)
        {
            DataTable changes = ((DataTable)dbView.DataSource).GetChanges();

            if (changes != null)
            {
                MySqlCommandBuilder mcb = new MySqlCommandBuilder(adapter);
                adapter.UpdateCommand = mcb.GetUpdateCommand();
                adapter.Update(changes);
                ((DataTable)dbView.DataSource).AcceptChanges();
            }
        }