#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();
}
}