錯誤寫法(拼接 SQL)
string sql = "select * from sentfile where FileName='" + fn + "'"; // 注入風險、格式錯誤
正確寫法:參數化 + ExecuteScalar
using (var conn = new SqlConnection(connStr))
using (var cmd = new SqlCommand("SELECT COUNT(1) FROM sentfile WHERE FileName=@fn", conn)) {
cmd.Parameters.AddWithValue("@fn", fn);
conn.Open();
int count = (int)cmd.ExecuteScalar();
if (count == 0) {
Console.WriteLine(fn + " 不存在,執行插入邏輯");
// 插入代碼
} else {
Console.WriteLine(fn + " 已存在,執行更新/跳過邏輯");
// 更新代碼
}
}
關鍵點解析
| 要點 | 說明 |
ExecuteScalar | 返回結果集第一行第一列,完美適配 COUNT(*) / MAX(id) 等聚合查詢,避免 SqlDataReader 開銷。 |
參數化 @fn | 防 SQL 注入,自動處理單引號、特殊字符,利用計劃緩存提升性能。 |
COUNT(1) vs COUNT(*) | 現代優化器等價,COUNT(1) 寫法略短。 |
| 唯一索引 | 在 FileName 列建立 UNIQUE INDEX,應用層可改為 INSERT ... ON DUPLICATE KEY UPDATE (MySQL) 或 MERGE (SQL Server) 實現原子 upsert。 |
EF Core 寫法(現代 ORM)
bool exists = await ctx.SentFiles.AnyAsync(f => f.FileName == fn);
if (!exists) { /* insert */ } else { /* update */ }
避坑提醒
- 切勿用
SELECT * 再判斷 reader.HasRows,多傳輸列數據、延遲釋放連接。
AddWithValue 可能推斷錯誤類型(如 string 推斷為 nvarchar(4000) 導致計劃不復用),關鍵路徑請顯式 cmd.Parameters.Add("@fn", SqlDbType.NVarChar, 255).Value = fn;。