我有一个DataGridView,它在表格中显示学生及其信息的列表。 一个名为“Grade”的列是可编辑的,因此我希望在用户单击“Save Changes”按钮时反映对数据库的所有更改。
我写过这段代码,但由于某些原因它不起作用:
private void bttnStudentsSaveChanges_Click(object sender, EventArgs e)
{
try
{
if (connection.State == ConnectionState.Closed) connection.Open();
DataTable changes = ((DataView)dataGridViewStudents.DataSource).Table.GetChanges();
if (changes != null)
{
foreach (DataRow row in changes.Rows)
{
MySqlCommand updateCommand = connection.CreateCommand();
updateCommand.CommandText = @"UPDATE grades
INNER JOIN lectures ON grades.idLecture = lectures.id
INNER JOIN students ON grades.idStudent = students.id
SET grades.grade = '" + row["Grade"] + @"'
WHERE students.id = '" + row["ID"] +
@"' AND (students.name = '" + row["Name"] +
@"' AND students.surname = '" + row["Surname"] +
"') AND lectures.name = '" + row["Lecture"] + "'";
updateCommand.ExecuteNonQuery();
}
}
}
catch (System.Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
}
执行此操作时,不会对数据库进行任何更改 因为我必须连接多个表,所以我不能使用MySqlCommandBuilder(至少我认为这是我尝试过它并且得到错误的原因)所以我决定手动完成。
我已经设置了几个断点来检查数据是否正确,changes
变量和CommandText
属性都包含有效数据。
我已经在SQLyog中测试了MySQL查询,它应该在那里工作
好像updateCommand.ExecuteNonQuery();
没有执行。
编辑:我添加了一些内容,但它仍无效。新代码是
private void bttnStudentsSaveChanges_Click(object sender, EventArgs e)
{
try
{
connection.Open();
DataTable changes = ((DataView)dataGridViewStudents.DataSource).Table.GetChanges();
if (changes != null)
{
foreach (DataRow row in changes.Rows)
{
MySqlCommand updateCommand = connection.CreateCommand();
updateCommand.CommandText = @"UPDATE grades
INNER JOIN lectures ON grades.idLecture = lectures.id
INNER JOIN students ON grades.IDStudent = students.ID
SET grades.grade = @grade
WHERE students.ID = @ID AND (students.name = @name AND students.surname = @surname)
AND lectures.name = @lecture";
updateCommand.Parameters.AddWithValue("@grade", row["Grade"]);
updateCommand.Parameters.AddWithValue("@ID", row["ID"]);
updateCommand.Parameters.AddWithValue("@name", row["Name"]);
updateCommand.Parameters.AddWithValue("@surname", row["Surname"]);
updateCommand.Parameters.AddWithValue("@lecture", row["Lecture"]);
updateCommand.ExecuteNonQuery();
}
}
}
catch (System.Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
finally
{
if(connection.State == ConnectionState.Open) connection.Close();
}
}
EDIT2:我发现ExecuteNonQuery
会返回一些受影响的行。结果我得到0。这是奇怪的,因为在SQLyog中执行命令会导致1行受到影响。怪异
EDIT3:我发现了问题所在。该数据库包含克罗地亚字母(čćšđž),因此当它们处于命令中时,命令不会执行。我认为这与字符编码有关。当命令只包含常规(ASCII)字母时,它会正常工作。我不知道如何修复它,但至少现在我知道问题在哪里
EDIT4:问题已解决。将数据库排序规则更改为utf8
答案 0 :(得分:1)
如果数据库类型中有整数,则不需要为参数指定单引号。 尝试没有数字类型的单打引号。
您可以使用参数化查询
来避免所有这些问题,更安全的方法修改强>
当你获得行值时,你可以根据类型获得它,如下所示
row.Field<int>("ID")
更改您的代码,如下所示,再次检查类型
updateCommand.Parameters.AddWithValue("@grade", row.Field<int>("Grade"));
updateCommand.Parameters.AddWithValue("@ID", row.Field<int>("ID"));
updateCommand.Parameters.AddWithValue("@name", row.Field<string>("Name"));
updateCommand.Parameters.AddWithValue("@surname", row.Field<string>("Surname"));
updateCommand.Parameters.AddWithValue("@lecture", row.Field<string>("Lecture");
答案 1 :(得分:1)
此代码非常脆弱。拿起一些连接而不确定它是否打开是不明白发生了什么的迹象。如果您甚至不知道您是否打开了连接,那么您可能不知道它是否参与了交易。我同意aquaraga - 它可能只是你纠缠不清你无法分辨。在代码中的其他地方可能存在另一个不提交的错误。
在任何情况下,我建议在打开连接时引入设计模式进行集中,创建事务然后执行工作然后提交或回滚。至少可以说,在UI事件中执行它是一个非常糟糕的做法。至少尝试将UI与业务和数据逻辑分开。