1. 程式人生 > >關於sqlhelper呼叫儲存過程和獲取引數返回值

關於sqlhelper呼叫儲存過程和獲取引數返回值

SQLHelper類給我們操作資料庫提供了便利,有些人說,SqlHelper類執行儲存過程無法獲取引數的返回值,這個認識是錯誤的。

SqlHelper類呼叫儲存過程的方法有下面類似的兩種型別:
public static int ExecuteNonQuery(string connectionString, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
public static int ExecuteNonQuery(string connectionString, string spName, params object[] parameterValues)

很多人沒注意到第一種呼叫方法是能執行儲存過程的,認為commandText引數只是傳遞sql命令,其實當CommandType 是儲存過程的時候,commandText可以是儲存過程的名字,看看SqlHelper上的引數說明:
/// <param name="connectionString">A valid connection string for a SqlConnection</param>
        /// <param name="commandType">The CommandType (stored procedure, text, etc.)</param>
        /// <param name="commandText">The stored procedure name or T-SQL command</param>
        /// <param name="commandParameters">An array of SqlParamters used to execute the command</param>
        /// <returns>An int representing the number of rows affected by the command</returns>
我開始也是沒注意這個問題,後來翻看它的原始碼才注意到了,前面嘗試呼叫第二方法來獲取返回值,其實這是無法獲取的。第二種呼叫說明上已經清楚的指出了不能獲取引數的返回值。
/// <remarks>
        /// This method provides no access to output parameters or the stored procedure's return value parameter.
仔細看的裡面的實現將會發現:
它呼叫了:GetSpParameterSet(connection, spName, false);
接著呼叫:GetSpParameterSetInternal(clonedConnection, spName, includeReturnValueParameter);
在GetSpParameterSetInternal裡面有這樣的判斷:
string hashKey = connection.ConnectionString + ":" + spName + (includeReturnValueParameter ? ":include ReturnValue Parameter":"");很顯然沒有返回值,然後在DiscoverSpParameterSet方法內通過

if (!includeReturnValueParameter)
    {
                cmd.Parameters.RemoveAt(0);//由於自動檢測引數時, 會在引數列表的首項加入@Return_Value.如果不需要它時,就要移去
    }
消除返回引數。其實由於第二種方法傳遞的是object型別的資料進去,根本就沒有把需要返回引數返回值這種資訊傳遞進去,程式無法知道你是不是需要返回引數的值。而且object型別是值型別,函式內改變它的值也帶不回來。之所以會有第二種呼叫方法是為了我們能更方便的呼叫儲存過程,不必去關係儲存過程引數名是什麼,知道它的引數順序就可以了,它主要是利用SqlCommandBuilder.DeriveParameters(cmd);來獲取引數資訊的,利用hashtable儲存了Parameters。(為什麼要用hashtable來儲存,不儲存應該也可以行的通的,還是從hashtable裡才clone一份Parameters出來用的。用靜態的hashtable儲存了最近一次呼叫的SqlParameter ,如果下次還是同一次呼叫,速度會快一些,不用去SqlCommandBuilder.DeriveParameters了,少連一次資料庫)第一種方法顯然是要麻煩很多,要建立SqlParameter

物件,還要注意儲存過程引數名稱等問題。下面是第一種方法呼叫例子:
string name;
        SqlParameter [] para=new SqlParameter[2];
        para[0]=new SqlParameter("@yhm","adm");
        para[1]=new SqlParameter("@name",SqlDbType.VarChar,100);
        para[1].Direction=ParameterDirection.Output;
        SqlHelper.ExecuteNonQuery(ConfigString.connectString, CommandType.StoredProcedure, "up_getUserName", para);
        name = para[1].Value.ToString();
        Response.Write(name);

其實很簡單,只是我們沒注意而已。sqlhelper內使用SqlConnection引數呼叫的話,將會根據SqlConnection的狀態來決定sqlhelper關不關閉SqlConnection。如果SqlConnection在傳入的時候是關閉的,那麼sqlhelper會自己開啟自己關閉;否則sqlhelper不會處理SqlConnection。