2018/04/14

SampleCMS 資料層元件說明:依照 Stored Procedure 建立基本的指令資訊類別 (DataAccessCommandInfo)

寫程式的過程中,我對於需要大量重覆編寫相同格式的程式碼難免會覺得枯燥乏味,例如在撰寫資料庫存取功能,已經花時間在資料庫寫好了取得員工資料的 Stored Procedure(以下簡稱 SP),接著還要再去資料層函式庫又寫一個取得員工資料的類別,寫的內容就像是換個格式重寫一樣的 SP 名稱與參數名單,難免覺得浪費了更多時間。

個人覺得寫程式最快的方式就是「複製、貼上、修改」,但前題是複製的來源程式碼最好是整理過的,不然很可能變成 -複製混亂、貼上混亂、修改更混亂-,造成後續維護的麻煩。

針對指令資訊類別 (DataAccessCommandInfo),我把開發過程中自己常用的格式整理成一份 DemoCommandInfos.cs (放在資料層函式庫的 namespace Common.DataAccess.DemoCommandInfos,只是方便自己需要時隨時打開來用),
以下說明,

DemoCommandInfos.cs 裡面放了4種基本的指令資訊類別格式,
    /// <summary>
    /// 1. 無參數
    /// </summary>
    public class spDemo_WoPara : IDataAccessCommandInfo
    {
        public CommandType GetCommandType()
        {
            return CommandType.StoredProcedure;
        }

        public string GetCommandText()
        {
            return "dbo.spDemo_WoPara";
        }
    }

    /// <summary>
    /// 2. 有參數
    /// </summary>
    public class spDemo_WithPara : IDataAccessCommandInfo
    {
        // DataAccessCommand 會使用欄位變數當做 SqlParameter 的產生來源(使用名稱、值);屬性不包含在其中。
        // 輸出參數請加上屬性 [OutputPara]
        public int pa1;
        public string pa2;

        public CommandType GetCommandType()
        {
            return CommandType.StoredProcedure;
        }

        public string GetCommandText()
        {
            return "dbo.spDemo_WithPara";
        }
    }

    /// <summary>
    /// 3. 有參數,輸出參數內容
    /// </summary>
    public class spDemo_WithOutputPara : IDataAccessCommandInfo
    {
        // DataAccessCommand 會使用欄位變數當做 SqlParameter 的產生來源(使用名稱、值);屬性不包含在其中。
        // 輸出參數請加上屬性 [OutputPara]
        public int pa1;
        public string pa2;
        public int ListMode;
        public int BeginNum;
        public int EndNum;
        public string SortField;
        public bool IsSortDesc;
        [OutputPara]
        public int RowCount;

        public CommandType GetCommandType()
        {
            return CommandType.StoredProcedure;
        }

        public string GetCommandText()
        {
            return "dbo.spDemo_WithOutputPara";
        }
    }

    /// <summary>
    /// 4. 有參數(加權限參數),輸出參數內容
    /// </summary>
    public class spDemo_WithOutputParaAndAuthPara : IDataAccessCommandInfo
    {
        // DataAccessCommand 會使用欄位變數當做 SqlParameter 的產生來源(使用名稱、值);屬性不包含在其中。
        // 輸出參數請加上屬性 [OutputPara]
        public int pa1;
        public string pa2;
        public int ListMode;
        public int BeginNum;
        public int EndNum;
        public string SortField;
        public bool IsSortDesc;
        public bool CanReadSubItemOfOthers;
        public bool CanReadSubItemOfCrew;
        public bool CanReadSubItemOfSelf;
        public string MyAccount;
        public int MyDeptId;
        [OutputPara]
        public int RowCount;

        public CommandType GetCommandType()
        {
            return CommandType.StoredProcedure;
        }

        public string GetCommandText()
        {
            return "dbo.spDemo_WithOutputParaAndAuthPara";
        }
    }

之前在資料層基本的呼叫方式內文中提到 SP 有「讀取資料用、新增用、更新用、刪除用」的差別,
不過對於指令資訊類別來說只有「有無參數、有無輸出型參數」的差別,上述 1~3 的類別格式範例就是這樣的差別而已。第 4 種類別格式範例只是為了個人方便,不想每次都重打 CanReadSubItemOfOthers, CanReadSubItemOfCrew, CanReadSubItemOfSelf, MyAccount, MyDeptId 這幾個成員變數,所以才多出這一種。


接下來我要示範當 SP 寫好之後,建立對應的指令資訊類別的步驟。
這次以新增員工身分資料來做為範例,下列是其 SP 的名稱與參數資訊,
-- =============================================
-- Author:      <lozen_lin>
-- Create date: <2017/11/11>
-- Description: <新增員工身分資料>
-- =============================================
create procedure dbo.spEmployeeRole_InsertData
@RoleName nvarchar(20)
,@RoleDisplayName nvarchar(20)
,@SortNo int
,@PostAccount varchar(20)
,@CopyPrivilegeFromRoleName nvarchar(20)
,@RoleId int output
as

開始建立指令資訊類別,

Step 1.
SP 有參數而且有輸出型的參數,到 DemoCommandInfos.cs 複製第 3 種的範例程式碼,並且貼上到 EmployeeAuthority.cs 的 namespace Common.DataAccess.EmployeeAuthority 區塊裡(因為這個 SP 歸類在帳號與權限系統)。
在 Visual Studio 之中點選綠框區可選擇 class name 快速跳到指定的程式碼
(這裡使用 Visual Studio Community 2015)

    /// <summary>
    /// 有參數,輸出參數內容
    /// </summary>
    public class spDemo_WithOutputPara : IDataAccessCommandInfo
    {
        // DataAccessCommand 會使用欄位變數當做 SqlParameter 的產生來源(使用名稱、值);屬性不包含在其中。
        // 輸出參數請加上屬性 [OutputPara]
        public int pa1;
        public string pa2;
        public int ListMode;
        public int BeginNum;
        public int EndNum;
        public string SortField;
        public bool IsSortDesc;
        [OutputPara]
        public int RowCount;

        public CommandType GetCommandType()
        {
            return CommandType.StoredProcedure;
        }

        public string GetCommandText()
        {
            return "dbo.spDemo_WithOutputPara";
        }
    }

Step 2.
從 SP 原始碼複製中、英文名稱並且取代類別的註解、類別名稱和 GetCommandText() 內容。
    /// <summary>
    /// 新增員工身分資料   <--改這邊
    /// </summary>
    public class spEmployeeRole_InsertData : IDataAccessCommandInfo   // <--改這邊
    {
        // DataAccessCommand 會使用欄位變數當做 SqlParameter 的產生來源(使用名稱、值);屬性不包含在其中。
        // 輸出參數請加上屬性 [OutputPara]
        public int pa1;
        public string pa2;
        public int ListMode;
        public int BeginNum;
        public int EndNum;
        public string SortField;
        public bool IsSortDesc;
        [OutputPara]
        public int RowCount;

        public CommandType GetCommandType()
        {
            return CommandType.StoredProcedure;
        }

        public string GetCommandText()
        {
            return "dbo.spEmployeeRole_InsertData";   // <--改這邊
        }
    }

Step 3.
從 SP 原始碼複製參數名單,換掉類別裡的成員變數。
    /// <summary>
    /// 新增員工身分資料
    /// </summary>
    public class spEmployeeRole_InsertData : IDataAccessCommandInfo
    {
        // DataAccessCommand 會使用欄位變數當做 SqlParameter 的產生來源(使用名稱、值);屬性不包含在其中。
        // 輸出參數請加上屬性 [OutputPara]
@RoleName nvarchar(20)                     // <--改這邊
,@RoleDisplayName nvarchar(20)
,@SortNo int
,@PostAccount varchar(20)
,@CopyPrivilegeFromRoleName nvarchar(20)
     [OutputPara]
,@RoleId int output

        public CommandType GetCommandType()
        {
            return CommandType.StoredProcedure;
        }

        public string GetCommandText()
        {
            return "dbo.spEmployeeRole_InsertData";
        }
    }

Step 4.
把類別裡的成員變數一個一個改為 c# 格式,完成!
    /// <summary>
    /// 新增員工身分資料
    /// </summary>
    public class spEmployeeRole_InsertData : IDataAccessCommandInfo
    {
        // DataAccessCommand 會使用欄位變數當做 SqlParameter 的產生來源(使用名稱、值);屬性不包含在其中。
        // 輸出參數請加上屬性 [OutputPara]
        public string RoleName;             // <--改這邊
        public string RoleDisplayName;      // <--改這邊
        public int SortNo;                  // <--改這邊
        public string PostAccount;          // <--改這邊
        public string CopyPrivilegeFromRoleName;      // <--改這邊
        [OutputPara]
        public int RoleId;                  // <--改這邊

        public CommandType GetCommandType()
        {
            return CommandType.StoredProcedure;
        }

        public string GetCommandText()
        {
            return "dbo.spEmployeeRole_InsertData";
        }
    }

以上就是個人每次在 SP 寫好之後,要建立對應的指令資訊類別所做的事情,每次4步驟完成,最後寫好的所有帳號與權限相關指令資訊類別就長這樣子 EmployeeAuthority.cs
(其實這4步驟應該可以自製一個 code generator 連線到資料庫,點選 SP 來產生 c# 程式碼,這個嘛...等我哪天覺得複製、貼上、修改多到累了再說吧。)

新增資料層程式只需要給個 SP 名稱、寫一次同樣的參數資訊就完成了,這樣真的很省事!
但需求總會出現例外,萬一想要客製化指令資訊類別的時候該怎麼做呢?例如:我想直接在資料層寫 sql script、我想在資料層開啟交易執行多個 SP。
後續我會繼續介紹~


沒有留言:

張貼留言