使用T4文字範本自動產生對應表之列舉(Enum)類別
前言
在系統開發過程中,會存在許多的對應表(Lookup Table)於資料庫中,而商業邏輯中又常以對應表內元素作為條件判斷的依據,因此為了提高程式碼的可讀性,通常都會建立對應表的列舉(Enum)類別來使用。
問題發生
以往在建立Enum類別時,會依照DB對應表目前存在資料,手動地依主鍵與名稱來逐筆新增Enum類別元素,確保Enum類別中各元素所表示的數值與對應表資料是一致的;但在開發初期,對應表的資料可能會依需求進行刪除及新增調整,此時就需要手動同步先前建立的Enum元素,使其與異動後對應表內容一致,其實是相當累人的。假使忘了同步調整Enum類別元素時,先前所建立的商業邏輯可能就因此整個錯亂了。
解決方案
因此為了避免這種問題的發生,筆者希望不要再透過人工來處理這段工作。我們可以透過T4文字範本,依據DB實際存在之資料來產出Enum類別及其元素;以下將針對此目標進行實作介紹。
建立T4文字範本
完整文字範本內容如下
<#@ include file="EF.Utility.CS.ttinclude"#>
<#@ import namespace="System.Data.SqlClient" #>
<#
// 設定連線字串
var connectionString = "Data Source=OOO; persist security info=True; initial catalog= OO; user id=OO;password=OO";
var descriptionColumnName = "Name"; // 設定Code Table中敘述欄位名稱 (作為列舉名稱之參考)
var enumNameSpace = "Domain.Enums"; // 設定NameSpace
var codeTableNames = new List<string>(){ // 設定所有Code Table名稱
"SysRole",
"ProductCategory"
};
// 變數宣告
var fileManager = EntityFrameworkTemplateFileManager.Create(this);
var codeGenerationTools = new CodeGenerationTools(this);
var connection = new SqlConnection(connectionString);
var command = connection.CreateCommand();
// 針對每個CodeTable來建立相對應的Enum類別
foreach (var tableName in codeTableNames)
{
connection.Open();
// 產生類別名稱
var enumName = tableName;
fileManager.StartNewFile(enumName + "Enum.cs");
#>
using System.ComponentModel;
namespace <#=enumNameSpace#>
{
public enum <#=tableName#>Enum
{
<#
command.CommandText = string.Format("SELECT * FROM {0}",codeGenerationTools.Escape(tableName));
var columnReader = command.ExecuteReader();
while (columnReader.Read())
{
// 產生列舉元素
if(!string.IsNullOrEmpty(columnReader[descriptionColumnName].ToString().Trim()))
{
#> [Description("<#=columnReader[descriptionColumnName].ToString()#>")]
<#=ConvertCaseString(columnReader[descriptionColumnName].ToString())#> = <#=columnReader[0].ToString()#>,
<# }
}#>
}
}
<#
connection.Close();
}
fileManager.Process();
#>
<#+
/// <summary>
/// Converts the phrase to specified convention.
/// </summary>
/// <param name="phrase"></param>
/// <param name="cases">The cases.</param>
/// <returns>string</returns>
public static string ConvertCaseString(string phrase)
{
phrase = phrase.ToLower().Replace("_", " ");
string[] splittedPhrase = phrase.Split(' ', '-', '.');
var sb = new StringBuilder();
sb = new StringBuilder();
foreach (String s in splittedPhrase)
{
char[] splittedPhraseChars = s.ToCharArray();
if (splittedPhraseChars.Length > 0)
{
splittedPhraseChars[0]
= ((new String(splittedPhraseChars[0], 1)).ToUpper().ToCharArray())[0];
}
sb.Append(new String(splittedPhraseChars));
}
return sb.ToString();
}
#>
請依實際環境調整以下相關資訊(連線字串、元素名稱參考欄位、須建立Enum的所有CodeTable名稱)
存檔後自動產出SysRoleEnum及ProductCategoryEnum兩個類別,而所包含元素將與DB對應表資料一致
參考資料
http://stackoverflow.com/questions/15060447/mapping-db-values-to-enum
http://www.codeproject.com/Articles/417283/Creating-Enums-from-Database-Lookup-Tables
希望此篇文章可以幫助到需要的人
若內容有誤或有其他建議請不吝留言給筆者喔 !