首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

SqlDataReader 執行帶輸出參數預存程序無法取得值的錯誤分析與解決

     編輯:關於.NET

問題現象

使用 SqlDataReader 執行含輸出參數的預存程序,讀取完資料流後嘗試取得 Parameter.Value 卻拋出例外或值為 null。

param[2].Direction = ParameterDirection.Output;
using (var reader = SQLHelper.ExecuteReader(sql, CommandType.StoredProcedure, param)) {
    while (reader.Read()) { list.Add(ConvertReaderToStudentModel(reader)); }
}
// 此處取得 param[2].Value 失敗
pageCount = (int)param[2].Value;

錯誤訊息:「無效嘗試在關閉的資料流上存取參數」**。

錯誤截圖

根因分析

SqlDataReader 以串流方式讀取結果集。輸出參數值僅在資料流完全關閉 (Reader 關閉) 後才由伺服器回填至 Parameter 集合。若在 using 區塊結束前 (Reader 尚未 Dispose/Close) 存取輸出參數,會導致錯誤。

正確模式

// 1. 設定輸出參數方向
param[2].Direction = ParameterDirection.Output;

// 2. 執行讀取
using (var reader = SQLHelper.ExecuteReader(sql, CommandType.StoredProcedure, param)) {
    while (reader.Read()) {
        list.Add(ConvertReaderToStudentModel(reader));
    }
    // Reader 仍開啟,此處不可存取輸出參數
}

// 3. Reader 已 Dispose/Close,輸出參數已回填,安全存取
pageCount = (int)param[2].Value;

關鍵點總結

錯誤做法正確做法
在 using (reader)... 區塊內存取輸出參數在 using 區塊**外部** (Reader 關閉後) 存取
未明確設定 ParameterDirection.Output執行前務必設定 param.Direction = ParameterDirection.Output
使用 ExecuteNonQuery 卻預期回傳結果集需結果集用 ExecuteReader,無結果集用 ExecuteNonQuery

進階:同時需結果集與輸出參數的最佳實踐

public PagedResult<T> ExecutePagedQuery<T>(string spName, SqlParameter[] parameters, 
    Func<SqlDataReader, T> mapFunc, string outputParamName)
{
    var outputParam = parameters.First(p => p.ParameterName == outputParamName);
    outputParam.Direction = ParameterDirection.Output;

    var list = new List<T>();
    using (var conn = new SqlConnection(connStr))
    using (var cmd = new SqlCommand(spName, conn) { CommandType = CommandType.StoredProcedure })
    {
        cmd.Parameters.AddRange(parameters);
        conn.Open();
        using (var reader = cmd.ExecuteReader())
        {
            while (reader.Read()) list.Add(mapFunc(reader));
        }
        // Reader 關閉後輸出參數才有值
        var totalCount = (int)outputParam.Value;
        return new PagedResult<T> { Items = list, TotalCount = totalCount };
    }
}

總結

SqlDataReader 串流特性決定輸出參數必須在 Reader 關閉後才能讀取。將存取邏輯移至 using 區塊外部即可解決此經典問題。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved