(讀取資料用的 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。

沒有留言:
張貼留言