我們可以利用code**藉由T4產生多個資料物件喔~^
**透過自訂 Attribute 來封裝 entity 與 DB 資料欄位的對應,
以企圖讓 data access layer 回來的資料,都是以 entity 物件的形式,
而非 DataTable 或 DataSet 這類弱型別的結構 .**
*難道每次設計 mapping table 的 entity 都只能手動去刻嗎?感覺好蠢、好浪費時間喔!! *
以 LINQ to SQL 或 LINQ to EF,都只需要拉一拉 data model,
就可以自動產生對應的entity 集合 ~*
*所以有很多人會自己寫對應的程式碼產生器,甚至許多套件也都有提供類似的功能 **
*是透過內建的 T4 轉換,用最簡單的方式來自動產生我們所需要的 entity class 檔案 !!
**註:有些人可能會說,為什麼不乾脆使用 LINQ to SQL 或 LINQ to EF,但實際上很多現實狀況,是不允許使用的。不管是 .net framework migration 的問題,或是 performance 問題,或是需要在DA層自訂一些客製化的動作時,就不一定可以直接使用 ~**
**T4 的全名是「Text Template Transformation Toolkit」,簡單的說,
就是一個可以轉換的文字範本,在範本裡面可以透過程式碼與邏輯,
來決定要嵌入哪些文字。幾乎現在的 Visual Studio 上 的 code generator --
--底子都是透過 T4 來產生對應的程式碼 ***
範例
需求說明:- 針對某一個DB中,某一張 table
- 產生對應的 class 內容
- Class 名稱預設與 table 名稱相同
- Property 名稱預設與 table column 名稱相同
- Property type 預設為 column type 所對應的 data type
- 每一個 property 上,要有對應的自訂 attribute,供 RowMapper 使用
- 可自行加入 todo 註解,或是相關 using namespace
**
*接著會出現下面的視窗,其實就是 T4 要幫忙轉換輸出結果的動作,
當按下確定,就會按照 tt 上的範本邏輯產生對應的程式碼。
第一次所產生的程式碼其實是空的,所以按確定跟取消都沒差*
*
**CODE**藉由T4產生多個資料物件喔~!^**
**需求是有現成的XML資料定義檔如下 **
*
<?xml version="1.0" encoding="utf-8" ?>
<datatable>
<table id="Running" version="1.0">
<col name="RunDateTime" datatype="System.DateTime" pkey="Y"/>
<col name="RunnerId" datatype="System.String" pkey="Y"/>
<col name="Record" datatype="System.String"/>
</table>
<table id="Runner" version="1.0">
<col name="RunnerId" datatype="System.String" pkey="Y"/>
<col name="Name" datatype="System.String" />
<col name="Birthday" datatype="System.DateTime" />
</table>
</datatable> *
**希望為其中每個Table各產生一個C#類別轡下: **
**using System.ComponentModel.DataAnnotations;
public class Runner{[Key]public System.String RunnerId { get; set; }
public System.String Name { get; set; }
public System.DateTime Birthday { get; set; }
} ***在過去,我會自己寫Code,解析XML文件再用StringBuilder組裝C#類別的內容。但既然已經學會T4範本程式產生器- 這等好物,自然沒有再走回頭路的道理。由XML產生C#類別的邏輯很簡單,唯一的小挑戰是一般T4範例多是一個.tt檔產生一個.cs檔,而這個需求得依照XML定義一次產生多個.cs檔案。爬文找到範例,單一.tt要輸出多個檔案的原理,是在執行過程------由GenerationEnvironment.ToString()取得當時累積的輸出結果,以File.WriteAllText()寫入檔案後,執行GenerationEnvironment.Clear()清掉------已寫到檔案的內容,再執行下個類別的程式碼產生邏輯。T4程式碼如下: **
****
<#@ template debug="true" hostSpecific="true" #>
<#@ output extension=".log" #>
<#@ Assembly Name="System.Core.dll" #>
<#@ Assembly Name="System.Windows.Forms.dll" #>
<#@ Assembly Name="System.Xml.dll" #>
<#@ Assembly Name="System.Xml.Linq.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Diagnostics" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Xml" #>
<#@ import namespace="System.Xml.Linq" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.Collections.Generic" #>
<#
string currPath = Path.GetDirectoryName(Host.TemplateFile);
XDocument xd = XDocument.Load(Path.Combine(currPath, "marathon.xml"));
foreach (var t in xd.Root.Elements()) {
string tableName = t.Attribute("id").Value;
#>
using System.ComponentModel.DataAnnotations;
public class <#= tableName #>
{
<#
foreach (var c in t.Elements()) {
string name = c.Attribute("name").Value;
string type = c.Attribute("datatype").Value;
bool isPK = c.Attribute("pkey") != null;
if (isPK) {
#>
[Key]
<#
}
#>
public <#= type #> <#= name #> { get; set; }
<#
}
#>
}
<#
string relativeOutputFilePath = "Code\\" + tableName + ".cs";
string outputFilePath = Path.Combine(currPath, relativeOutputFilePath);
TemplateHelper.WriteTemplateOutputToFile(outputFilePath, GenerationEnvironment);
}
#>
<#+
//REF: http://bit.ly/X9wTu0
public class TemplateHelper
{
public static void WriteTemplateOutputToFile(
string outputFilePath,
System.Text.StringBuilder genEnvironment)
{
System.IO.File.WriteAllText(outputFilePath, genEnvironment.ToString());
genEnvironment.Clear();
}
}
#>
**補充**
:
- 預設T4並未參照System.Xml.dll及System.Xml.Linq.dll,
- 記得要在最前方透過<#@ Assembly #>及<#@ import #>加入參照。
- 透過Host.TemplateFile可取得T4檔案所在實體路徑,可用來決定輸出檔案路徑。
- T4檔末端透過<#+ #>宣告了共用函數TemplateHelper.WriteTemplateOutputToFile(),
- 透過其將產生結果寫入檔案 .
- ****
- &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
- &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&