1

学生のリストとその情報をテーブルに表示する DataGridView があります。「グレード」という名前の1つの列は編集可能であるため、ユーザーが「変更を保存」ボタンをクリックしたときにすべての変更をデータベースに反映したいと考えています。

私はこのコードを書きましたが、何らかの理由で機能しません:

    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

データベース タイプに整数がある場合は、パラメータに一重引用符を付ける必要はありません。数値型の単一引用符なしで試してください。

これらの問題をすべて回避でき、より安全な方法は、パラメーター化されたクエリを使用することです

編集

行の値を取得すると、以下のようにタイプに基づいて取得できます

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 に答える
1

このコードは危険なほど脆弱です。いくつかの接続を拾い上げて、それが開いているかどうかさえわからないということは、何が起こっているのか本当にわからないという兆候です. 接続が開いているかどうかさえわからない場合は、トランザクションに関与しているかどうかがわからない可能性があります。私はaquaragaに同意します-おそらくそうですが、あなたはとても絡み合っているので、わかりません. コミットしないコードの別の場所に別のバグがある可能性があります。

いずれにせよ、接続を開いてトランザクションを作成し、作業を行ってからコミットまたはロールバックするときに一元化する設計パターンを導入することをお勧めします。UI イベントでそれを行うのは、控えめに言ってもかなり悪い習慣です。少なくとも、UI をビジネスおよびデータ ロジックから分離するようにしてください。

于 2013-06-02T14:23:07.570 に答える