C# ADO.NET 呼叫預存程序與 SqlDataReader
呼叫 SQL Server 預存程序,透過 SqlDataReader 串流讀取查詢結果,重點整理:
SqlCommand.CommandType = CommandType.StoredProcedure指定執行預存程序- 使用
SqlParameter傳入預存程序參數 ExecuteReader(CommandBehavior.CloseConnection)讀取串流資料- 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 重要特性
- 僅向前、唯讀:只能透過
Read()往下逐列讀取,無法回頭,也不能修改資料 - 佔用資料庫連線:Reader 開啟期間,同一連線無法執行其他動作
- 一定要釋放資源:手動呼叫
reader.Close(),優先建議使用using自動釋放 - 兩種讀取欄位的寫法:
csharp reader[0]; // 使用索引讀取 reader["Title"]; // 使用欄位名稱(可讀性較佳)
常見問題
- 忘記設定
CommandType.StoredProcedure→ 執行失敗 - 參數名稱大小寫、拼寫與預存程序不一致 → 參數比對失敗
- Reader 沒有關閉 → 連線持續被佔用,造成連線集區耗盡
- 於
while(reader.Read())內部執行新查詢:同一個連線不能同時擁有多個 Reader - 預存程序缺少參數、參數型別不符 → 執行報錯
執行方法比較
| 執行方式 | 適用情境 | 回傳物件 |
|---|---|---|
| ExecuteNonQuery | 新增、更新、刪除的預存程序 | 受影響列數 int |
| ExecuteScalar | 回傳單列單欄(聚合查詢) | object |
| ExecuteReader | 回傳多筆資料集 | SqlDataReader(串流讀取) |
SqlDataReader
Previous: SqlTransaction 資料庫事務
Next: SqlDataAdapter