3

私は専門的なプログラミングの経験は比較的ありませんが、MS Access データベースとやり取りするプログラムを作成しようとしています。基本的に、フォームで情報を収集し、エントリごとに新しい行で情報を渡そうとしています。私は開いている OleDbConnection を持っており、新しいエントリを持つ行を確認できることをテストで示していますが、送信ボタンを押すと、キャッチにエラーは表示されませんが、データベースは変更されません。私は元々、クリック イベントから呼び出したメソッドにコードを持っていましたが、コードをイベント ハンドラーに渡して、呼び出しに問題がないことを確認しました。

private void btnSubmit_Click(object sender, EventArgs e)
    {

        if (DBConnection.State.Equals(ConnectionState.Closed))
        {
            DBConnection.Open();
        }

        try
        {
            MessageBox.Show("Save Data at index: " + intRowPosition.ToString());

            OleDbCommand OledbInsert = new OleDbCommand("Insert INTO RetentionTable (DateTime,Center,CSP,MemberID,ContractNumber,RetentionType,RetentionTrigger,MemberReason,ActionTaken,Other) VALUES('" + DateTime.Now.ToString() + "','" + GetCenter("") + "','" + GetName("") + "','" + GetMemberID("") + "','" + GetContractNumber("") + "','" + GetType("") + "','" + GetTrigger("") + "','" + GetReason("") + "','" + GetAction("") + "', + GetOther("")," DBConnection);

            intRowPosition++;
        }

        catch (Exception ex)
        {
            MessageBox.Show(ex.Message.ToString());
            MessageBox.Show(ex.StackTrace.ToString());
        }
        finally
        {
            RefreshDBConnection();
        }

    }

これが書かれていない理由についてのアイデアは大歓迎です。

4

2 に答える 2

7

上記のコードには多くの問題があります。

  • まず、コマンドは単に宣言するのではなく、実行する必要があります。(これが、データベースが変更されていない理由です)
  • 次に、ステートメントで予約済みのキーワードを使用します(そのため、ステートメントを実行しても失敗し、例外がスローされます)。
  • 3 番目に、文字列を連結してコマンド テキストを作成します。アプリケーションがSQL インジェクション攻撃を受けやすくなる非常に悪い動き
  • 第四に、使用後に接続を閉じる必要があります

代わりのコードを書いてみましょう

string cmdText = "Insert INTO RetentionTable " +
                "([DateTime],Center,CSP,MemberID,ContractNumber,RetentionType," + 
                "RetentionTrigger,MemberReason,ActionTaken,Other) " + 
                "VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
 using(OleDbConnection cn = new OleDbConnection(conString))
 using(OleDbCommand cmd = new OleDbCommand(cmdText, cn))
 {
    cmd.Parameters.AddWithValue("@p1", DateTime.Now.ToString());
    cmd.Parameters.AddWithValue("@p2", GetCenter("")); 
    cmd.Parameters.AddWithValue("@p3", GetName(""));
    cmd.Parameters.AddWithValue("@p4", GetMemberID(""));
    cmd.Parameters.AddWithValue("@p5", GetContractNumber(""));
    cmd.Parameters.AddWithValue("@p6", GetType("")); 
    cmd.Parameters.AddWithValue("@p7", GetTrigger(""));
    cmd.Parameters.AddWithValue("@p8", GetReason(""));
    cmd.Parameters.AddWithValue("@p9", GetAction(""));
    cmd.Parameters.AddWithValue("@p10", GetOther(""));
    cmd.ExecuteNonQuery();
 }

DATETIME は Access の予約済みキーワードであるため、列名に使用する場合は角かっこで囲む必要があります。

文字列の連結は MSAccess では悪い習慣ですが、コードがSQL インジェクションに使用される可能性がある他のデータベースでは致命的な欠陥です(Access ではより困難ですが、不可能ではありません)。この例のようにパラメーター化されたクエリを使用すると、SQL インジェクションの問題が解消されますが、日付、文字列、および小数に必要な正しい書式設定を使用して、フレームワーク コードが正しい値をデータベース エンジンに渡すこともできます。

考慮すべきもう 1 つのポイントは、グローバルな OleDbConnection オブジェクトを持たず、必要なときにオブジェクトを作成、使用、および破棄することです。接続プーリングはパフォーマンスの問題を回避し、何らかの理由で接続が失敗したときにコードがメモリ リークに悩まされることはありません。

また、 GetXXXXXメソッドはすべて文字列を返すように見えることも付け加えたいと思います。これらのメソッドは、書き込み先の基になるデータベース フィールドと互換性のある値を返す必要があることに注意してください。

于 2013-07-03T14:43:08.010 に答える
1

データベースに入れている値の周りのスピーチマークかもしれません。アポストロフィに変更してみてください。

とにかく、最終的な SQL を文字列に保存してログ ファイルまたは画面に出力し、それを Access SQL エディターにコピーして実行することを強くお勧めします。次に、エラーがあるかどうかとその内容を確認します。

于 2013-07-03T14:39:56.050 に答える