回傳值定義 (MSDN)
| SQL 命令類型 |
成功時回傳 |
失敗/無影響時 |
| INSERT / UPDATE / DELETE |
受影響的資料列數 (int >= 0) |
0 (無符合條件列) |
| CREATE TABLE / DDL / SET 陳述式 |
-1 |
拋出 Exception |
| 預存程序 (無 SET NOCOUNT ON) |
受影響列數 |
0 或 -1 |
| 預存程序 (SET NOCOUNT ON) |
-1 |
-1 |
為什麼不能只寫 if (rows > 0)?
// 建立資料表
string ddl = "CREATE TABLE Demo (Id INT PRIMARY KEY)";
int result = cmd.ExecuteNonQuery(); // 成功回傳 -1,而非 1
if (result > 0) // 錯誤!會誤判為失敗
Console.WriteLine("成功"); // 不會執行
else
Console.WriteLine("失敗或無影響"); // 錯誤訊息
正確判斷模式
模式 A:DML (增刪改) → 檢查 > 0
int affected = cmd.ExecuteNonQuery();
if (affected > 0)
// 確實有資料異動
else
// 無資料符合條件 (WHERE 不匹配) 或嘗試插入重複鍵被忽略
模式 B:DDL / 結構變更 → 捕捉 Exception
try
{
int result = cmd.ExecuteNonQuery(); // 成功通常 -1
// 不檢查 result,沒拋出例外即代表成功
}
catch (SqlException ex) when (ex.Number == 2714) // 資料表已存在
{
// 處理已存在情況
}
catch (Exception ex)
{
// 記錄日誌、回滾、拋出
}
模式 C:預存程序 → 使用 OUTPUT 參數或 RETURN VALUE
var cmd = new SqlCommand("usp_UpdateStock", conn) { CommandType = CommandType.StoredProcedure };
cmd.Parameters.Add("@ProductId", SqlDbType.Int).Value = 100;
var retParam = cmd.Parameters.Add("@Result", SqlDbType.Int);
retParam.Direction = ParameterDirection.ReturnValue;
cmd.ExecuteNonQuery();
int spResult = (int)retParam.Value; // 由 SP 定義:0=成功, -1=庫存不足, -2=商品不存在
// 依 spResult 判斷業務邏輯
實務封裝建議:統一回傳結構
public class DbResult
{
public bool Success { get; set; }
public int AffectedRows { get; set; }
public string Message { get; set; }
public Exception Exception { get; set; }
}
public static DbResult ExecuteNonQuerySafe(string sql, params SqlParameter[] parameters)
{
var result = new DbResult();
try
{
using (var conn = new SqlConnection(ConnStr))
using (var cmd = new SqlCommand(sql, conn))
{
if (parameters != null) cmd.Parameters.AddRange(parameters);
conn.Open();
result.AffectedRows = cmd.ExecuteNonQuery();
result.Success = true;
}
}
catch (Exception ex)
{
result.Success = false;
result.Exception = ex;
result.Message = ex.Message;
}
return result;
}
關鍵提醒
- 永遠包裹 try-catch:DDL、權限不足、死結、網路中斷皆會拋出例外。
- 預存程序加
SET NOCOUNT ON:避免干擾回傳值,改用 OUTPUT/RETURN VALUE 傳遞業務狀態。
- 異步版本:.NET 4.5+ 使用
ExecuteNonQueryAsync 配合 CancellationToken。
- 交易控制:多條 DML 需包在
SqlTransaction 中,統一 Commit/Rollback。