提供的程式碼存在嚴重安全與維護性問題:
using System;
using System.Data.SqlClient;
using System.Windows.Forms;
public void SaveCourse(string courseId, string courseName) {
if (string.IsNullOrWhiteSpace(courseId) || string.IsNullOrWhiteSpace(courseName)) {
MessageBox.Show("請輸入課程號和課程名!");
return;
}
const string connStr = "Server=.;Database=Students;Integrated Security=True;";
const string checkSql = "SELECT COUNT(1) FROM Course WHERE CourseId = @Id OR CourseName = @Name";
const string insertSql = "INSERT INTO Course (CourseId, CourseName) VALUES (@Id, @Name)";
const string updateSql = "UPDATE Course SET CourseName = @Name WHERE CourseId = @Id";
using (var conn = new SqlConnection(connStr))
using (var cmd = conn.CreateCommand()) {
conn.Open();
using (var tran = conn.BeginTransaction()) {
cmd.Transaction = tran;
try {
// 檢查是否存在
cmd.CommandText = checkSql;
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("@Id", courseId);
cmd.Parameters.AddWithValue("@Name", courseName);
int exists = (int)cmd.ExecuteScalar();
if (exists > 0) {
var result = MessageBox.Show("課程已存在,是否更新?", "確認",
MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
if (result == DialogResult.OK) {
cmd.CommandText = updateSql;
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("@Id", courseId);
cmd.Parameters.AddWithValue("@Name", courseName);
cmd.ExecuteNonQuery();
MessageBox.Show("更新成功!");
}
} else {
cmd.CommandText = insertSql;
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("@Id", courseId);
cmd.Parameters.AddWithValue("@Name", courseName);
cmd.ExecuteNonQuery();
MessageBox.Show("新增成功!");
}
tran.Commit();
} catch (Exception ex) {
tran.Rollback();
MessageBox.Show("操作失敗:" + ex.Message);
}
}
}
}
| 原寫法 | 改進寫法 | 效益 |
|---|---|---|
| 字串拼接 SQL | 參數化 `@Id`, `@Name` | 防 SQL Injection、計畫快取重用 |
| 多次 Open/Close | `using` 區塊自動管理連線生命週期 | 資源釋放確定、程式碼簡潔 |
| 無事務 | `BeginTransaction` / `Commit` / `Rollback` | 資料一致性保障 |
| 中文欄位名 | 英文欄位名 (CourseId, CourseName) | 跨平台相容、維護性高 |
C# 參數化查詢詳細教學:C# SQL 參數化查詢完整範例
「參數化查詢」是 ADO.NET 開發的鐵律,「using + 事務」是資源管理的標準模式。重構後的程式碼更安全、更易讀、更易維護。