(讀取資料用的 SP 名稱為 dbo.spTableName_GetData 或是 dbo.spTableName_GetList、
新增用的 SP 名稱為 dbo.spTableName_InsertData、
更新用的 SP 名稱為 dbo.spTableName_UpdateData、
刪除用的 SP 名稱為 dbo.spTableName_DeleteData)
因此本系統的資料層元件是以執行 SP 做為主軸來設計,
以下說明基本的呼叫方式,
下圖是資料層的主要元件關聯圖,
下列程式碼是呼叫者端要取得員工資料的範例,也就是上圖左側 Caller use 的位置。
(本系統遵循三層式系統設計原則,資料層的呼叫者只有邏輯層的元件)
public DataSet GetEmployeeData(string empAccount) { IDataAccessCommand cmd = DataAccessCommandFactory.GetDataAccessCommand(DBs.MainDB); spEmployee_GetData cmdInfo = new spEmployee_GetData() { EmpAccount = empAccount }; DataSet ds = cmd.ExecuteDataset(cmdInfo); dbErrMsg = cmd.GetErrMsg(); return ds; } public class DBs { public static IDataAccessSource MainDB { get { return new DataAccessSource("DBConnString"); } } } public class spEmployee_GetData : IDataAccessCommandInfo { // DataAccessCommand 會使用欄位變數當做 SqlParameter 的產生來源(使用名稱、值);屬性不包含在其中。 // 輸出參數請加上屬性 [OutputPara] public string EmpAccount; public CommandType GetCommandType() { return CommandType.StoredProcedure; } public string GetCommandText() { return "dbo.spEmployee_GetData"; } }
以下參照程式碼行號做說明,
Line 3: 呼叫者需要存取資料庫,因此透過簡單工廠 DataAccessCommandFactory 取得一個指令執行者的物件 (cmd),拿回來的物件只需透過介面 IDataAccessCommand 操作。
Line 4~7: spEmployee_GetData 就是元件關聯圖中 spDemo_WithPara 的位置,spEmployee_GetData 是一個實作 IDataAccessCommandInfo 介面的類別,它用來描述資料庫中的 SP: dbo.spEmployee_GetData 的名稱與參數資訊,使用它 new 出指令資訊物件 (cmdInfo) 並且設定好參數值,準備丟給指令執行者 (cmd) 去執行。
Line 9: 將指令資訊物件 (cmdInfo) 丟給指令執行者 (cmd) 去執行取回填入資料的 DataSet,執行過程中指令執行者 (cmd) 會自動抓取指令資訊物件 (cmdInfo) 的成員變數,依照成員變數的名稱,將其值傳送給 SP 的同名參數,此次範例的成員變數只有 string EmpAccount 一個(在倒數第 12 行)。
Line 10: 使用指令執行者 (cmd) 的 GetErrMsg() 取得錯誤訊息,萬一有異常錯誤時可使用。
不只是讀取資料,新增資料、更新資料、刪除資料皆以這樣的寫法去呼叫對應的 SP,差別只有在 Line 9 的部分,把 cmd.ExecuteDataset(cmdInfo); 更改為 cmd.ExecuteNonQuery(cmdInfo);
下列程式碼是呼叫者端要新增員工資料的範例,
public bool InsertEmployeeData(AccountParams param) { IDataAccessCommand cmd = DataAccessCommandFactory.GetDataAccessCommand(DBs.MainDB); spEmployee_InsertData cmdInfo = new spEmployee_InsertData() { EmpAccount = param.EmpAccount, EmpPassword = param.EmpPassword, EmpName = param.EmpName, Email = param.Email, Remarks = param.Remarks, DeptId = param.DeptId, RoleId = param.RoleId, IsAccessDenied = param.IsAccessDenied, StartDate = param.StartDate, EndDate = param.EndDate, OwnerAccount = param.OwnerAccount, PasswordHashed = param.PasswordHashed, DefaultRandomPassword = param.DefaultRandomPassword, PostAccount = param.PostAccount }; bool result = cmd.ExecuteNonQuery(cmdInfo); dbErrMsg = cmd.GetErrMsg(); if (result) { param.EmpId = cmdInfo.EmpId; } else if (cmd.GetSqlErrNumber() == 50000 && cmd.GetSqlErrState() == 2) { param.HasAccountBeenUsed = true; } return result; } public class spEmployee_InsertData : IDataAccessCommandInfo { // DataAccessCommand 會使用欄位變數當做 SqlParameter 的產生來源(使用名稱、值);屬性不包含在其中。 // 輸出參數請加上屬性 [OutputPara] public string EmpAccount; public string EmpPassword; public string EmpName; public string Email; public string Remarks; public int DeptId; public int RoleId; public bool IsAccessDenied; public DateTime StartDate; public DateTime EndDate; public string OwnerAccount; public bool PasswordHashed; public string DefaultRandomPassword; public string PostAccount; [OutputPara] public int EmpId; public CommandType GetCommandType() { return CommandType.StoredProcedure; } public string GetCommandText() { return "dbo.spEmployee_InsertData"; } }
在這個範例中比較特別的是,SP 有定義一個 output 參數,下列為 SP 的參數定義部分。
create procedure dbo.spEmployee_InsertData @EmpAccount varchar(20) ,@EmpPassword varchar(128) ,@EmpName nvarchar(50) ,@Email varchar(100) ,@Remarks nvarchar(200) ,@DeptId int ,@RoleId int ,@IsAccessDenied bit ,@StartDate datetime ,@EndDate datetime ,@OwnerAccount varchar(20) ,@PasswordHashed bit ,@DefaultRandomPassword varchar(50) ,@PostAccount varchar(20) ,@EmpId int output as
為了要讓指令執行者 (cmd) 能夠幫忙接回執行 SP 之後的 @EmpId 值,指令資訊 class spEmployee_InsertData 必須要在 public int EmpId 加上 [OutputPara] 這個自訂屬性。
這樣子指令執行者 (cmd) 在執行 SP 之後就會把 SP 的 @EmpId 值傳給指令資訊物件 (cmdInfo) 的 EmpId。
Line 27: 從指令資訊物件 (cmdInfo) 取回 EmpId 值。
Line 29: 若執行 SP 發生錯誤時,利用 cmd.GetSqlErrNumber(), cmd.GetSqlErrState() 取回資料庫的 Error Number 和 Error State 值,可做進一步的處理。
下列程式碼是呼叫者端要更新員工資料的範例,
public bool UpdateEmployeeData(AccountParams param) { IDataAccessCommand cmd = DataAccessCommandFactory.GetDataAccessCommand(DBs.MainDB); spEmployee_UpdateData cmdInfo = new spEmployee_UpdateData() { EmpId = param.EmpId, EmpPassword = param.EmpPassword, EmpName = param.EmpName, Email = param.Email, Remarks = param.Remarks, DeptId = param.DeptId, RoleId = param.RoleId, IsAccessDenied = param.IsAccessDenied, StartDate = param.StartDate, EndDate = param.EndDate, OwnerAccount = param.OwnerAccount, PasswordHashed = param.PasswordHashed, DefaultRandomPassword = param.DefaultRandomPassword, MdfAccount = param.PostAccount }; bool result = cmd.ExecuteNonQuery(cmdInfo); dbErrMsg = cmd.GetErrMsg(); return result; } public class spEmployee_UpdateData : IDataAccessCommandInfo { // DataAccessCommand 會使用欄位變數當做 SqlParameter 的產生來源(使用名稱、值);屬性不包含在其中。 // 輸出參數請加上屬性 [OutputPara] public int EmpId; public string EmpPassword; public string EmpName; public string Email; public string Remarks; public int DeptId; public int RoleId; public bool IsAccessDenied; public DateTime StartDate; public DateTime EndDate; public string OwnerAccount; public bool PasswordHashed; public string DefaultRandomPassword; public string MdfAccount; public CommandType GetCommandType() { return CommandType.StoredProcedure; } public string GetCommandText() { return "dbo.spEmployee_UpdateData"; } }
下列程式碼是呼叫者端要刪除員工資料的範例,
public bool DeleteEmployeeData(int empId) { IDataAccessCommand cmd = DataAccessCommandFactory.GetDataAccessCommand(DBs.MainDB); spEmployee_DeleteData cmdInfo = new spEmployee_DeleteData() { EmpId = empId }; bool result = cmd.ExecuteNonQuery(cmdInfo); dbErrMsg = cmd.GetErrMsg(); return result; } public class spEmployee_DeleteData : IDataAccessCommandInfo { // DataAccessCommand 會使用欄位變數當做 SqlParameter 的產生來源(使用名稱、值);屬性不包含在其中。 // 輸出參數請加上屬性 [OutputPara] public int EmpId; public CommandType GetCommandType() { return CommandType.StoredProcedure; } public string GetCommandText() { return "dbo.spEmployee_DeleteData"; } }
- 上述資料層元件皆放置於組件 Common.DataAccess.dll 之中。
- 簡單工廠 DataAccessCommandFactory、資料存取來源介面 IDataAccessSource 以及指令執行者介面 IDataAccessCommand,放在 namespace Common.DataAccess。
- 帳號與權限系統相關的 SP 指令資訊類別,皆放在 namespace Common.DataAccess.EmployeeAuthority。
- 網頁內容發佈系統相關的 SP 指令資訊類別,皆放在 namespace Common.DataAccess.ArticlePublisher。
- class DBs 屬於呼叫者的管理範圍,放在 namespace Common.LogicObject。
沒有留言:
張貼留言