[C#][T4] 使用T4文字範本自動產生對應表之列舉(Enum)類別

  • 2067
  • 0
  • C#
  • 2015-03-10

使用T4文字範本自動產生對應表之列舉(Enum)類別

前言

 

在系統開發過程中,會存在許多的對應表(Lookup Table)於資料庫中,而商業邏輯中又常以對應表內元素作為條件判斷的依據,因此為了提高程式碼的可讀性,通常都會建立對應表的列舉(Enum)類別來使用。

 

image

 

 

問題發生

 

以往在建立Enum類別時,會依照DB對應表目前存在資料,手動地依主鍵與名稱來逐筆新增Enum類別元素,確保Enum類別中各元素所表示的數值與對應表資料是一致的;但在開發初期,對應表的資料可能會依需求進行刪除及新增調整,此時就需要手動同步先前建立的Enum元素使其與異動後對應表內容一致,其實是相當累人的。假使忘了同步調整Enum類別元素時,先前所建立的商業邏輯可能就因此整個錯亂了。

 

image

 

 

解決方案

 

因此為了避免這種問題的發生,筆者希望不要再透過人工來處理這段工作。我們可以透過T4文字範本,依據DB實際存在之資料來產出Enum類別及其元素;以下將針對此目標進行實作介紹。

 

建立T4文字範本

image

 

完整文字範本內容如下


<#@ 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名稱)

 

image

 

存檔後自動產出SysRoleEnum及ProductCategoryEnum兩個類別,而所包含元素將與DB對應表資料一致

 

image

image

image

 

 

參考資料

 

http://stackoverflow.com/questions/15060447/mapping-db-values-to-enum

http://www.codeproject.com/Articles/417283/Creating-Enums-from-Database-Lookup-Tables


希望此篇文章可以幫助到需要的人

若內容有誤或有其他建議請不吝留言給筆者喔 !