3

パスワード変更フォームを作成しています。フォームを実行してテキストボックスに入力すると、メッセージで例外が発生しますThere is already and open DataReader associated with this command which must be closed first

彼は私が使用しているコードです:

private bool CompareStrings(string string1, string string2)
        {
            return String.Compare(string1, string2, true, System.Globalization.CultureInfo.InvariantCulture) == 0 ? true : false;
        }

    private void button1_Click(object sender, EventArgs e)
    {
        try
        {
            SqlConnection con1 = new SqlConnection();
            con1.ConnectionString = "data source=.;Initial catalog=inventory;Integrated Security=true";
            con1.Open();

            SqlCommand cmd = new SqlCommand("SELECT ISNULL(username, '') AS username, ISNULL(password,'') AS password FROM login WHERE username='" + textBox1.Text + "' and password='" + textBox2.Text + "'", con1);

            SqlDataReader dr = cmd.ExecuteReader();

            string userText = textBox1.Text;
            string passText = textBox2.Text;

            while (dr.Read())
            {
                if (this.CompareStrings(dr["username"].ToString(), userText) &&
                    this.CompareStrings(dr["password"].ToString(), passText))
                {
                    SqlCommand cmd2 = new SqlCommand("UPDATE login SET password='" + textBox3.Text + "'where username='" + textBox1.Text + "'", con1);
                    cmd2.ExecuteNonQuery();
                    MessageBox.Show("Password Changed Successfully");
                }
                else
                {
                    MessageBox.Show("Incorrect Old password");                        
                }

            }

            dr.Close();

            con1.Close();

        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
4

2 に答える 2

2

SqlDataReader同じ接続で が開いている間は、コマンドを実行できません。コードを変更するには、次の 2 つのいずれかを実行できます。

  1. 2 番目の接続を作成し、その 2 番目の接続で更新クエリを実行します。

  2. リーダーからのデータを保存し、リーダーを閉じてから、すべてのデータを更新します。あなたの場合、すべてのユーザー名を保存して更新し、それらを 1 つの更新クエリで更新することができます。Username in (<yourlisthere>)

于 2013-10-28T20:43:36.120 に答える
2

DataReader を開くと、接続は DataReader からの要求のみを処理します。ログイン テーブルの更新に使用される SqlCommand を実行できません。

これを接続文字列に追加しない限り

MultipleActiveResultSets = True;

ここでは、MARS への参照を見つけることができます。

そして、ここでDataReaderに関するMSDNの言葉

SqlDataReader が使用されている間、関連付けられた SqlConnection は SqlDataReader を提供するためにビジー状態であり、SqlConnection を閉じる以外の操作は実行できません。これは、SqlDataReader の Close メソッドが呼び出されるまでのケースです。たとえば、Close を呼び出すまで、出力パラメーターを取得することはできません。

補足ですが、非常に重要です。文字列連結を使用して SQL コマンドを作成しないでください。常にパラメーター化されたクエリを使用する

string cmdText = "UPDATE login SET password=@pwd where username=@usr";
using(SqlCommand cmd2 = new SqlCommand(cmdText, con1))
{
    cmd2.Parameters.AddWithValue("@pwd", textBox3.Text);
    cmd2.Parameters.AddWithValue("@usr", textBox1.Text);
    cmd2.ExecuteNonQuery();    
}

パラメーター化されたクエリは、SQL インジェクションの問題を回避し、コマンド テキストを簡素化します。
これは、コードの先頭にある SELECT クエリにも当てはまります。ユーザーからの入力を信頼しないでください

知っておくべきもう 1 つの問題は、データベースにクリア テキストのパスワードを保存することです。これは、セキュリティの観点から非常に悪い習慣と見なされます。パスワードにハッシュ関数を適用し、結果を保存する必要があります。正しいパスワードを確認しながら、ユーザー入力に対してハッシュ関数を繰り返し、データベースに保存されているハッシュ化されたパスワードに対して結果を確認します

于 2013-10-28T20:43:49.183 に答える