SqlDataReader

C# ADO.NET 呼叫預存程序與 SqlDataReader

呼叫 SQL Server 預存程序,透過 SqlDataReader 串流讀取查詢結果,重點整理:

  1. SqlCommand.CommandType = CommandType.StoredProcedure 指定執行預存程序
  2. 使用SqlParameter傳入預存程序參數
  3. ExecuteReader(CommandBehavior.CloseConnection) 讀取串流資料
  4. SqlDataReader 屬於僅向前、唯讀的串流讀取器,使用完務必關閉

預存程序定義

必須先在資料庫建立好預存程序,才能進行呼叫。

create proc myProc
@id int
as
select * from [dbo].[Article] where id>@id
go

-- 測試呼叫
exec myProc @id=5Code language: JavaScript (javascript)

接收參數@id,撈出 Article 資料表內 id 大於傳入值的資料列。

於 C# 呼叫預存程序

透過 ExecuteReader 取得 SqlDataReader,用來讀取多筆結果。

string connectionString = "Data Source=.;Initial Catalog=db;Integrated Security=SSPI;";
using (SqlConnection conn = new SqlConnection(connectionString))
{
    conn.Open();
    SqlCommand sqlCom = new SqlCommand();
    sqlCom.Connection = conn;
    sqlCom.CommandText = "myProc";
    sqlCom.CommandType = CommandType.StoredProcedure;

    SqlParameter param = new SqlParameter("@id", SqlDbType.Int, 8);
    param.Value = 4;
    param.Direction = ParameterDirection.Input;
    sqlCom.Parameters.Add(param);

    SqlDataReader reader = sqlCom.ExecuteReader(CommandBehavior.CloseConnection);
    StringBuilder sb = new StringBuilder();
    while (reader.Read())
    {
        sb.AppendLine(reader[0] + "-" + reader[1]);
    }
    reader.Close();
    MessageBox.Show(sb.ToString());
}Code language: C# (cs)
透過 using 釋放讀取器,避免資源洩漏
string connectionString = "Data Source=.;Initial Catalog=db;Integrated Security=SSPI;";
using (SqlConnection conn = new SqlConnection(connectionString))
{
    conn.Open();
    using (SqlCommand sqlCom = new SqlCommand("myProc", conn))
    {
        sqlCom.CommandType = CommandType.StoredProcedure;//宣告命令為預存程序
        // 加入輸入參數
        sqlCom.Parameters.Add("@id", SqlDbType.Int).Value = 4;

        // CommandBehavior.CloseConnection:讀取器關閉時自動關閉連線
        using (SqlDataReader reader = sqlCom.ExecuteReader(CommandBehavior.CloseConnection))
        {
            StringBuilder sb = new StringBuilder();
            while (reader.Read())
            {
                // reader[0] 代表第1欄,reader[1] 代表第2欄;也可寫 reader["欄位名稱"]
                sb.AppendLine($"{reader[0]}-{reader[1]}");
            }
            MessageBox.Show(sb.ToString());
        }
        // 不用手動呼叫 reader.Close(),using 會自動釋放資源
    }
}Code language: C# (cs)

CommandType 的三種列舉值

  • CommandType.Text:執行一般 SQL 陳述式
  • CommandType.StoredProcedure執行預存程序
  • CommandType.TableDirect:直接讀取資料表

若未設定 StoredProcedure,程式會把預存程序名稱當成一般 SQL 執行,直接引發錯誤!

SqlParameter 參數方向

  • ParameterDirection.Input:輸入參數(傳入數值,最常使用)
  • ParameterDirection.Output:輸出參數
  • ParameterDirection.InputOutput:可輸入亦可輸出雙向參數
  • ParameterDirection.ReturnValue:預存程序傳回值

CommandBehavior.CloseConnection 的作用

SqlDataReader 呼叫 Close() 或是被釋放時,自動關閉對應的 SqlConnection
適用場景:方法回傳 Reader 物件,外部程式讀完資料後連線自動回收。

SqlDataReader 重要特性

  1. 僅向前、唯讀:只能透過 Read() 往下逐列讀取,無法回頭,也不能修改資料
  2. 佔用資料庫連線:Reader 開啟期間,同一連線無法執行其他動作
  3. 一定要釋放資源:手動呼叫 reader.Close(),優先建議使用 using 自動釋放
  4. 兩種讀取欄位的寫法:
    csharp reader[0]; // 使用索引讀取 reader["Title"]; // 使用欄位名稱(可讀性較佳)

常見問題

  1. 忘記設定 CommandType.StoredProcedure → 執行失敗
  2. 參數名稱大小寫、拼寫與預存程序不一致 → 參數比對失敗
  3. Reader 沒有關閉 → 連線持續被佔用,造成連線集區耗盡
  4. while(reader.Read()) 內部執行新查詢:同一個連線不能同時擁有多個 Reader
  5. 預存程序缺少參數、參數型別不符 → 執行報錯

執行方法比較

執行方式適用情境回傳物件
ExecuteNonQuery新增、更新、刪除的預存程序受影響列數 int
ExecuteScalar回傳單列單欄(聚合查詢)object
ExecuteReader回傳多筆資料集SqlDataReader(串流讀取)

SqlDataReader

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *