System.ArgumentException: 另一個SqlParameterCollection中已包含SqlParameter。

赤砂之蠍我愛羅發表於2012-12-10

 一般情況下,我們定義的一個SqlParameter引數陣列,如:

            SqlParameter[] parms = 
            {
                new SqlParameter("@DateTime1", dtBegin),
                new SqlParameter("@DateTime2", dtEnd)
            };

如果只給一個SqlCommand使用,這種情況的引數使用,不會出現異常,但如果該引數陣列同時給兩個Sqlcommand使用,就會出現如下異常:

  System.ArgumentException: 另一個SqlParameterCollection中已包含SqlParameter

        原因如下:宣告的SqlParameter陣列,而在迴圈的內部,每一次執行ExecuteNonQuery(或者其它命令方法)都由該方法內部的IDbCommand.Parameters.Add(IDbDataParameter)將SqlParameter陣列新增到IDbCommand的IDataParameterCollection中。而framework機制限制兩個IDataParameterCollection指向同一個對象。雖然ExecuteNonQuery方法內部宣告瞭一個IDbCommand的臨時物件,理論上講,這個包含了IDataParameterCollection的IDbCommand物件會在ExecuteNonQuery方法結束時從記憶體中釋放。但是實際上可能是由於垃圾回收機制並沒有將IDbCommand臨時物件即時的回收,而且改物件繫結的Parameter集合也存在,就像一個DropDownList新增Item一樣。這樣在下一個迴圈執行的時候,會導致兩個IDataParameterCollection指向同一個物件,此時出現問題。
解決方案一:在每一次迴圈時,重新生成物件,但這樣會產生大量的垃圾變數,不可取。
解決方案二:將使用完之後的Command命令的Parameters集合清空。推薦使用,類似程式碼如下:

        /// <summary>
        /// 獲取一個DataTable
        /// </summary>
        public static DataTable GetDataTable(
            string connDBStr, string sql, params SqlParameter[] cmdParms)
        {
            SqlCommand cmd = new SqlCommand();
            using (SqlConnection conn = new SqlConnection(connDBStr))
            {
                PrepareSqlCommand(cmd, conn, null, sql, cmdParms);
                SqlDataAdapter da = new SqlDataAdapter(cmd);
                DataTable dt = new DataTable    (SetSqlAsDataTableName(sql));
                da.Fill(dt);
                cmd.Parameters.Clear();//多了這一句,就解決了問題
                return dt;
            }
        }

另外,如果不是陣列,只是一個SqlParameter變數,如:

            SqlParameter parm = 
                new SqlParameter("@Cust_Id", CustId.Trim());

則多次被SqlCommand使用,不會出現問題,我已經做了試驗!




原文來自:黃永泰 http://www.cnblogs.com/OldYongs/archive/2011/03/12/1982021.html

相關文章