創建代碼生成器可以很簡單:如何通過T4模板生成代碼?[下篇]
在《上篇》中我們通過T4模板為我們指定的數據表成功生成了我們需要的用於添加、修改和刪除操作的存儲過程。但是這是一種的解決方案,即我們必須為每一個生成的存儲過程建立一個模板。如果我們提供一種的代碼生成方式,將會為編程人員帶來極大的便利。借助於T4 ToolBox這個開源工具箱,多文件的SQL Generator的實現變得異常簡單。[文中的例子可以從這裏下載]
目錄
一、多文件代碼生成器會帶來多大的便利?
二、創建自定義的Generator
三、ProcedureGenerator如何被使用?
我們先來直觀的感受一下較之《上篇》提供的單一文件的代碼生成器,基於多文件的代碼生成解決方案會為開發人員帶來多大的便利。
同樣對於《上篇》創建的數據表T_PRODUCT,之前我們為了生成三個不同的存儲過程,我們不得已需要創建3個不同的T4模板文件。實際上我們更需要的方式隻需要創建,讓我們的SQL Generator自動為我們生成如左圖所示(點擊看大圖)。
有的時候,基於單個數據表的存儲過程生成方式我們依然覺得不方便。如果我們能夠在T4模板文件中指定的,讓我們的SQL Generator為列表的每一個數據表都生成CUD三個存儲過程,這樣的方式更加具有吸引力。如右圖所示(點擊看大圖),一個訂單模塊包含兩個具有主子關係的兩張表(T_ORDER和T_ORDER_DETAIL),現在我們在一個T4模板中指定這兩個表明,通過SQL Generator可以幫助我們生成6個包含存儲過程的.sql附屬文件。
甚至有的時候我們連數據表列表都無需指定,讓SQL Generator為都生成相應的存儲過程。我的例子中沒有提供這樣的功能,但是實現自來不會存在任何問題。
在《上篇》中我創建了一個抽象的類,以及三個基於生成CUD存儲過程的具體ProcedureTemplate:InsertProcedureTemplate、和。它們都將直接服務於我們今天將要提供的基於多文件的SQL Generator。
在《上篇》中,這四個Template分別定義在4個不同的TT文件中,3個具體的ProcedureTemplate通過<#@include>指令將抽象ProcedureTemplate模板文件包含過來。由於我們將要創建的T4模板將會使用到這四個類,如果我們用四個<#@include>指令將四個TT文件包含過來,由於T4引擎將會導致對ProcedureTemplate的4次包含,最好將會導致變異問題。個人覺得這應該算是T4引擎解析包含關係的一個局限性,為了解決這個問題我們不得不抽象的ProcedureTemplate和三個具體的ProcedureTemplate都。
T4 ToolBox為類庫中為了提供了一個抽象的類用於實現多文件的代碼生成。為此我們創建一個TT模板文件,定義了如下一個繼承自該類的ProcedureGenerator。ProcedureGenerator的核心是通過屬性Templates定義的類型為IEnumerable<ProcedureTemplate>的ProcedureTemplate列表,這個列表在存儲過程中進行初始化。而對於ProcedureGenerator的構造函數,處理定義了一個表示數據庫連接字符串的databaseName的參數外,並以數組參數的形式指定了生成的存儲過程基於的。
<#@ import namespace="System.Collections.Generic" #>
<#@ include file="ProcedureTemplate.tt" #>
<#@ include file="T4Toolbox.tt" #>
<#+
public class ProcedureGenerator : Generator
{
public IEnumerable<ProcedureTemplate> Templates{get; private set;}
public ProcedureGenerator(string databaseName, params string[] tableNames)
{
if(null == tableNames || tableNames.Length == 0)
{
throw new ArgumentNullException("tableNames");
}
this.Templates = InitlizeTemplates(databaseName,tableNames);
}
private IEnumerable<ProcedureTemplate> InitlizeTemplates(string databaseName, string[] tableNames)
{
foreach(string tableName in tableNames)
{
yield return new InsertProcedureTemplate(databaseName, tableName);
yield return new UpdateProcedureTemplate(databaseName, tableName);
yield return new DeleteProcedureTemplate(databaseName, tableName);
}
}
protected override void RunCore()
{
foreach(ProcedureTemplate tempalte in this.Templates)
{
tempalte.RenderToFile(tempalte.GetProcedureName() + ".sql");
}
}
}
#>
真正的存儲過程的T-SQL腳本實現在重寫的RunCore中。由於具體的文本轉化邏輯都定義在了ProcedureTemplate中了,所以在這裏我們需要遍曆的ProcedureTemplate集合中每一個Template對象,調用方法將相應的存儲過程的腳本寫入以存儲過程命名同名的.sql文件中。
我們最後來看看我們創建的ProcedureGenerator最終如何被應用於具體的代碼生成。其實很簡單,我們隻需要創建相應的模板文件,通過<#@include>將定義ProcedureGenerator類的TT文件包含近來,最後以代碼語句調用塊(<#StatementCode#>)的形式實力化該對象,並調用方法即可。在構造函數中指定數據庫連接字符串的名稱和數據表名的列表。下麵是基於但表的T4模板。
<#@ template language="C#" hostSpecific="true" debug="true" #>
<#@ include file="Templates\ProcedureGenerator.tt" #>
<#
new ProcedureGenerator("TestDb","T_PRODUCT").Run();
#>
下麵是基於多表的T4模板:
<#@ template language="C#" hostSpecific="true" debug="true" #>
<#@ include file="Templates\ProcedureGenerator.tt" #>
<#
new ProcedureGenerator("TestDb","T_ORDER","T_ORDER_DETAIL").Run();
#>
當你代碼生成工作執行之後,,你需要手工刪除掉它。
從數據到代碼——通過代碼生成機製實現強類型編程[上篇]
從數據到代碼——通過代碼生成機製實現強類型編程[下篇]
從數據到代碼——基於T4的代碼生成方式
創建代碼生成器可以很簡單:如何通過T4模板生成代碼?[上篇]
創建代碼生成器可以很簡單:如何通過T4模板生成代碼?[下篇]
微信公眾賬號:大內老A
微博:www.weibo.com/artech
如果你想及時得到個人撰寫文章以及著作的消息推送,或者想看看個人推薦的技術資料,可以掃描左邊二維碼(或者長按識別二維碼)關注個人公眾號(原來公眾帳號蔣金楠的自媒體將會停用)。
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁麵明顯位置給出原文連接,否則保留追究法律責任的權利。
最後更新:2017-10-27 14:04:33