1

我有一个 DataGridView,它在表格中显示学生列表及其信息。一列名为“等级”是可编辑的,因此我希望在用户单击“保存更改”按钮时反映对数据库的所有更改。

我写了这段代码,但由于某种原因它不起作用:

    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

4

2 回答 2

1

这段代码非常脆弱。拿起一些连接并且不确定它是否打开是不知道发生了什么的标志。如果你甚至不知道你是否打开了一个连接,那么你可能不知道它是否在进行交易。我同意 aquaraga - 它可能是,但你只是纠缠不清,你无法分辨。代码中其他地方可能存在另一个未提交的错误。

在任何情况下,我都建议引入一种设计模式,以便在您打开连接、创建事务然后执行工作然后提交或回滚时进行集中处理。至少可以说,在 UI 事件中这样做是一种非常糟糕的做法。至少尝试将您的 UI 与您的业务和数据逻辑分开。

于 2013-06-02T14:23:07.570 回答
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");
于 2013-06-02T12:36:55.103 回答