今天一個查詢需要透過ExcuteReader 回傳結果集,同時又想輸出參數,剛開始的時候一直得不到輸出參數的值,以為預存程序出錯,但是在查詢分析器裡面測試是正確的,而且輸出參數確實已經賦值。
更讓人百思不得其解的是,對出輸出強制型別轉換丟出異常之後,確又可以得到了,難道是ado.net 的bug,想像頁不可能啊,這麼常用的API,不可能出這種錯吧,我的程式碼類似一下場景:
try {
using (SqlDataReader dr = cmd.ExecuteReader(CommandBehavior.CloseConnection)) {
int val = (int)cmd.Parameters[1].Value; // 現在還是空值
// more
}
}
catch(Exception exp) {
throw new ApplicationException("輸出參數值:" + cmd.Parameters[1].Value, exp); // 現在可以得到輸出值了
}
真是鬱悶慘,足足調試追蹤一個小時
終於還是在MSDN中找到了答案:
當您將Command 物件用於預存程序時,可以將Command 物件的CommandType 屬性設定為StoredProcedure。當CommandType 為StoredProcedure 時,可以使用Command 的Parameters 屬性來存取輸入及輸出參數和回傳值。無論呼叫哪一個Execute 方法,都可以存取Parameters 屬性。但是,當呼叫ExecuteReader 時,在DataReader 關閉之前,將無法存取返回值和輸出參數。
ref: http://msdn2.microsoft.com/zh-CN/library/tyy0sz6b.aspx
原來如此啊,覺得又被MS忽悠了,想來,誰叫自己學藝不經啊,而且早改查文檔
回到自己的程式碼環境,還是可以解釋的。
因為當catch到Expception 的時候已經跳出using 範圍了,DataReader已經自動被關閉了,自然可以得到輸出參數的值。
當然,如果把try catch 放到using中還是得不到的,因為還在using範圍內,DataReader並沒有被關閉。
另外,MSDN中說只有關閉DataReader才可以訪問,其實不然。
經過測試,可以總結如下:
1。對於ExecuteReader而言,Output parm 和returnvalue 作為結果集傳回DataReader,而改結果集總是在最後一個。
2。根據1,當有結果集時,要存取輸出參數和傳回值,需要呼叫NextResult 到輸出參數和傳回值對應的結果集位置
3。根據1 ,當Execute沒有傳回結果集時,就可以直接存取(注意,無需呼叫Read())
4。特別注意的對於傳回多個結果集的,需要呼叫多次NextResult;如果結果集數又是動態的,那麼當nextResult()的回傳值為false就是了。
5。即使ExecuteReader指定了選項CommandBehavior.SingleResult(傳回單一結果集,其實是傳回批次的第一個結果集),輸出參數也會作為一個結果集傳回。
6。關閉DataReader(Close()),會填入輸出參數,因此可以存取。
7。由於DataReader是唯讀向前的,因此,即使是透過在關閉DataReader之前透過NextResult方問到了輸出參數,先前的結果集都無法在存取了(某些情況,可能想透過輸出參數來動態控制結果集的訪問)。
8。為解決6中的問題,可以將不使用輸出參數,直接將輸出參數作為第一個結果返回(SELECT @parmname)
以上只是,自己的總結,希望沒有出入,對初學者也許有幫助。
ref:
http://www.bigcircleboy.net/583a194f-2c2c-4662-9036-4e2f0eb262396084313157728108.html