1

次のコード(ここでは読みやすさのための疑似値を使用)があり、最初の接続で大量のデータ(数千行)が返されます。SqlDataReaderは、それらを1つずつ読み取りreader.Read()、新しい接続を開いて各行を新しい値で更新します。

using (SqlConnection conn = new SqlConnection(connString))
    using (SqlCommand cmd = new SqlCommand("sp1", conn))
    {
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.AddWithValue("@param1", param1);
        cmd.Connection.Open();
        using (SqlDataReader reader = cmd.ExecuteReader())
        {
            while (reader.Read())
            {
                try
                {
                    string hash= utils.SHA256.Hashing((string)reader["firstRow"], saltValue);
                    using (SqlConnection conn2 = new SqlConnection(connString))
                    using (SqlCommand cmd2 = new SqlCommand("sp2", conn2))
                    {
                        cmd2.CommandType = CommandType.StoredProcedure;
                        cmd2.Parameters.AddWithValue("@param1", param1);
                        cmd2.Parameters.AddWithValue("@param2", param2);
                        cmd2.Connection.Open();
                        cmd2.ExecuteNonQuery();
                    }
                }
                catch (SqlException ex)
                {
                    //something
                }
            }
        }
    }

しかし、それはエラーをスローします:

[InvalidOperationException: Invalid attempt to call Read when reader is closed.]
System.Data.SqlClient.SqlDataReader.ReadInternal(Boolean setTimeout) +640
System.Data.SqlClient.SqlDataReader.Read() +9

開発環境では正常に機能しますが、ここでは数百行しかありません。すぐにエラーがスローされるので、ある種のタイムアウトのようには見えませんが、ちょっと-わかりません...

4

1 に答える 1

5

なぜそれが起こるのかはわかりませんが、同じデータベースへのライブ接続を繰り返しながらクエリを実行することは本当に悪い考えです。DataReaderを使用してレコードを反復処理する限り、接続は有効であることに注意してください。

さらに悪いのは、接続をすばやく連続して何千回も開いてから閉じることです。これだけで、あらゆるデータベースをひざまずくことができます。

ロジックを変更し、必要な値をローカル変数に格納し(構造は関係ありません)、1つの接続のみを使用して、必要なすべてのストアドプロシージャを実行します。

例えば:

using (SqlConnection conn = new SqlConnection(connString))
{
    conn.Open();

    List<string[]> values = new List<string[]>();
    using (SqlCommand cmd = new SqlCommand("sp1", conn))
    {
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.AddWithValue("@param1", param1);
        using (SqlDataReader reader = cmd.ExecuteReader())
        {
            while (reader.Read())
            {
                try
                {
                    string hash= utils.SHA256.Hashing((string)reader["firstRow"], saltValue);
                    string anotherValue = (string)reader["secondRow"];
                    values.Add(new string[] { hash, anotherValue });
                }
                catch (SqlException ex)
                {
                    //something
                }
            }
            reader.Close();
        }
    }

    if (values.Count > 0)
    {
        using (SqlCommand cmd2 = new SqlCommand("sp2", conn))
        {
            cmd2.CommandType = CommandType.StoredProcedure;
            cmd2.Parameters.AddWithValue("@param1", null);
            cmd2.Parameters.AddWithValue("@param2", null);
            values.ForEach(items =>
            {
                cmd2.Parameters["@param1"].Value = items[0];
                cmd2.Parameters["@param2"].Value = items[1];
                cmd2.ExecuteNonQuery();
            });
        }
    }
    conn.Close();
}

すべてのストアドプロシージャを実行するための1つの接続、1つのコマンド。本当にそれ以上は必要ありません。

于 2012-11-19T14:44:02.313 に答える