資料庫端:建立預存程序
無參數查詢
CREATE PROC usp_GetAllStudents
AS
SELECT * FROM StudentInfo;
有參數查詢
CREATE PROC usp_GetStudentByIdName
@StudentId VARCHAR(10),
@StudentName VARCHAR(10)
AS
SELECT * FROM StudentInfo
WHERE StudentId = @StudentId AND StudentName = @StudentName;
C# 呼叫端:無參數情況
using (SqlConnection conn = new SqlConnection(connString))
using (SqlCommand cmd = new SqlCommand("usp_GetAllStudents", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
conn.Open();
// 方式一:DataReader
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
Console.WriteLine($"{reader["StudentId"]} - {reader["StudentName"]}");
}
}
// 方式二:填充 DataTable
DataTable dt = new DataTable();
using (SqlDataAdapter adapter = new SqlDataAdapter(cmd))
{
adapter.Fill(dt);
}
}
C# 呼叫端:有參數情況
using (SqlConnection conn = new SqlConnection(connString))
using (SqlCommand cmd = new SqlCommand("usp_GetStudentByIdName", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
// 參數添加方式一:AddWithValue (簡易,但類型推斷可能不精確)
cmd.Parameters.AddWithValue("@StudentId", "S001");
cmd.Parameters.AddWithValue("@StudentName", "王小明");
// 參數添加方式二:明確指定型別與長度 (推薦,效能較好)
cmd.Parameters.Add("@StudentId", SqlDbType.VarChar, 10).Value = "S001";
cmd.Parameters.Add("@StudentName", SqlDbType.VarChar, 10).Value = "王小明";
// 參數添加方式三:取得參數物件後設定值 (需重複使用時)
SqlParameter idParam = cmd.Parameters.Add("@StudentId", SqlDbType.VarChar, 10);
idParam.Value = "S001";
conn.Open();
using (SqlDataReader reader = cmd.ExecuteReader())
{
// 處理結果...
}
}
參數方向與輸出參數
// 預存程序有 OUTPUT 參數時
cmd.Parameters.Add("@ReturnCode", SqlDbType.Int).Direction = ParameterDirection.Output;
cmd.Parameters.Add("@ReturnMsg", SqlDbType.NVarChar, 200).Direction = ParameterDirection.Output;
conn.Open();
cmd.ExecuteNonQuery();
int code = (int)cmd.Parameters["@ReturnCode"].Value;
string msg = (string)cmd.Parameters["@ReturnMsg"].Value;
最佳實踐總結
| 建議 | 說明 |
| 使用 using 區塊 | 確保連線、命令、讀取器正確釋放 |
| 明確指定 SqlDbType | 避免 AddWithValue 的型別推斷開銷與計畫快取問題 |
| 設定參數長度 | VarChar/NVarChar 建議指定長度,匹配資料庫定義 |
| 參數化查詢 | 預存程序本身即參數化,防止 SQL Injection |
| CommandTimeout | 複雜預存程序需適當調大 cmd.CommandTimeout |
Entity Framework Core 呼叫方式 (補充)
// EF Core 2.1+
var students = context.Students
.FromSqlRaw("EXEC usp_GetStudentByIdName @StudentId, @StudentName",
new SqlParameter("@StudentId", "S001"),
new SqlParameter("@StudentName", "王小明"))
.ToList();
// 純量輸出/無結果集
context.Database.ExecuteSqlRaw("EXEC usp_UpdateStats");