承接上篇 (新增修改),本文說明 DataAccessLayer (DAL) 的查詢方法:RunSqlDataTable、RunSqlDataSet、RunSqlStrings、RunSqlDataRow、RunSqlGetID、RunSqlStringsByRow,以及交易控制用法。
| 方法 | 回傳型別 | 適用場景 |
|---|---|---|
| RunSqlDataTable(sql) | DataTable | 單一結果集、直接繫結 GridView/Repeater |
| RunSqlDataSet(sql) | DataSet | 多結果集 (多條 SQL 以分號分隔) |
| RunSqlStrings(sql) | string[] | 單筆記錄、欄位較少、輕量傳遞 |
| RunSqlDataRow(sql) | DataRow | 單筆記錄、需透過欄位名稱存取 |
| RunSqlGetID(sql) | string | 單一標量值 (COUNT、SUM、MAX、IDENTITY) |
| RunSqlStringsByRow(sql) | string[] | 多筆記錄、僅需第一欄值陣列 |
// 1. 取得 DataTable - 單一查詢
string sql = "SELECT Col1, Col2, Col3 FROM TableName WHERE Condition = @p";
DataTable dt = dal.RunSqlDataTable(sql, new SqlParameter("@p", value));
gv.DataSource = dt; gv.DataBind();
// 2. 取得 DataSet - 多查詢一次往返
sql = "SELECT * FROM Table1; SELECT * FROM Table2; SELECT * FROM Table3";
DataSet ds = dal.RunSqlDataSet(sql);
// ds.Tables[0] → Table1 資料
// ds.Tables[1] → Table2 資料
// ds.Tables[2] → Table3 資料
// 3. 取得單筆記錄 - string[] (輕量)
sql = "SELECT Col1, Col2, Col3 FROM TableName WHERE ID = 1";
string[] values = dal.RunSqlStrings(sql); // values[0], values[1], values[2]
// 4. 取得單筆記錄 - DataRow (可用欄位名)
DataRow dr = dal.RunSqlDataRow(sql);
string col1 = dr["Col1"].ToString();
// 5. 取得標量值 (計數、總和、新增後 ID)
sql = "SELECT COUNT(*) FROM TableName WHERE KindID = 1";
string count = dal.RunSqlGetID(sql);
sql = "SELECT SCOPE_IDENTITY()"; // 新增後取得 IDENTITY
string newId = dal.RunSqlGetID(sql);
// 6. 取得多筆記錄的第一欄陣列
sql = "SELECT ID FROM TableName WHERE KindID = 1";
string[] ids = dal.RunSqlStringsByRow(sql); // ["1", "5", "12", ...]
// DAL 內部需暴露 Connection/Transaction 或提供 BeginTransaction/Commit/Rollback
// 範例假設 DAL 有以下成員:
// SqlConnection Connection { get; }
// SqlTransaction CurrentTransaction { get; set; }
// void BeginTrans()
// void CommitTrans()
// void RollbackTrans()
try {
dal.BeginTrans();
// 多步驟操作
dal.RunSql("INSERT INTO Orders ...", params);
dal.RunSql("UPDATE Inventory SET Qty = Qty - @qty WHERE ProductID = @pid", params);
dal.RunSql("INSERT INTO OrderLogs ...", params);
dal.CommitTrans();
} catch (Exception ex) {
dal.RollbackTrans();
throw; // 或記錄日誌後拋出自訂例外
}
// 避免 SQL Injection,一律使用參數
string sql = "SELECT * FROM Users WHERE Username = @user AND Status = @status";
var parameters = new[] {
new SqlParameter("@user", username),
new SqlParameter("@status", 1)
};
DataTable dt = dal.RunSqlDataTable(sql, parameters);
現代架構建議 DAL 回傳 Entity 或 DTO,由上層決定是否轉 DataTable 給舊版控制項。
<connectionStrings>
<add name="DefaultConn"
connectionString="Data Source=.;Initial Catalog=MyDB;Integrated Security=True"
providerName="System.Data.SqlClient" />
</connectionStrings>
// DAL 建構式
public DataAccessLayer() {
string connStr = ConfigurationManager.ConnectionStrings["DefaultConn"].ConnectionString;
_conn = new SqlConnection(connStr);
}