- Visual Studio 2015高级编程(第6版)
- (美)Bruce Johnson
- 1236字
- 2021-03-19 15:26:57
14.6 生成代码资源
开发企业应用程序时,常常会遇到很少变化的引用数据,它们在代码中表示为一个枚举类型。使数据库中的数据与枚举类型的值同步是一个耗时、重复的任务,非常适于用T4模板自动完成。本节的模板将连接AdventureWorks示例数据库,并根据Person.ContactType表的内容创建一个枚举。
C#
<<#@ template debug="false" hostspecific="false" language="C#" #> <#@ output extension=".generated.cs" #> <#@ assembly name="System.Data" #> <#@ import namespace="System.Data.SqlClient" #> <#@ import namespace="System.Text.RegularExpressions" #> <# var connectionString = "Data Source=.\\SQLEXPRESS; Initial Catalog=AdventureWorks;" + "Integrated Security=true;"; var sqlString = "SELECT ContactTypeID, [Name] FROM [Person].[ContactType]"; #> // This code is generated. Please do not edit it directly // If you need to make changes please edit ContactType.tt instead namespace AdventureWorks { public enum ContactType { <# using(var conn = new SqlConnection(connectionString)) using(var cmd = new SqlCommand(sqlString, conn)) { conn.Open(); var contactTypes = cmd.ExecuteReader(); while( contactTypes.Read() ) { #> <#= ValidIdentifier( contactTypes[1].ToString() ) #> = <#=contactTypes[0]#>, <#} conn.Close(); } #> } } <#+ public string ValidIdentifier(string input) { return Regex.Replace(input, @"[^a-zA-Z0-9]", String.Empty ); } #>
VB
<#@ template debug="false" hostspecific="false" language="VB" #> <#@ output extension=".generated.vb" #> <#@ assembly name="System.Data" #> <#@ import namespace="System.Data.SqlClient" #> <#@ import namespace="System.Text.RegularExpressions" #> <# Dim ConnectionString as String = "Data Source=.\SQLEXPRESS; " _ & "Initial Catalog=AdventureWorks; Integrated Security=true;" Dim SqlString as String = "SELECT ContactTypeID,[Name] FROM [Person].[ContactType]" #> ' This code is generated. Please do not edit it directly ' If you need to make changes please edit ContactType.tt instead Namespace AdventureWorks Enum ContactType <# Using Conn As New SqlConnection(ConnectionString), _ Cmd As New SqlCommand(SqlString, Conn) Conn.Open() Dim ContactTypes As SqlDataReader = Cmd.ExecuteReader() While ContactTypes.Read() #> <#= ValidIdentifier( contactTypes(1).ToString() ) #> = <#=contactTypes(0)#> <# End While Conn.Close() End Using #> End Enum End Namespace <#+ Public Function ValidIdentifier(Input as String) As String Return Regex.Replace(Input, "[^a-zA-Z0-9]", String.Empty ) End Function #>
上述示例中使用的AdventureWorks数据库可从http://msftdbprodsamples.codeplex.com下载。可在该站点上找到如何安装此数据库的指示,并且可能需要修改用于该示例中的连接字符串,以符合自己的SQL环境。
第一部分由T4指令组成。前两个指令指定模板的语言和输出文件的扩展名。第三个指令把一个程序集附加到生成器上(以访问System.Data.SqlClient名称空间),最后两个指令把模板代码需要的名称空间导入模板。
下一部分是一个T4 Statement块,它包含一些模板要使用的变量。把它们放在模板文件的顶部,将便于在需要修改时找到它们。
在变量声明的后面是一个T4 Text块,其中包含一些解释性的注释、一个名称空间和一个枚举声明。它们会全部复制到生成的输出文件中。通常最好在生成的文件中提供一个注释,说明数据的来源和编辑方式。这可以防止重新生成文件后删除修改时的意外事故。
模板的剩余部分是一个Statement块。这个块使用第一个Statement块中定义的变量,创建并打开一个与AdventureWorks数据库的连接。接着查询数据库,用数据读取器检索需要的数据。
对于每条从数据库中提取的记录,都产生一个Text块。这个Text块包含两个用等号隔开的Expression块。第二个表达式仅把Contact类型的ID添加到生成的输出文件中。第一个表达式调用在Class Feature块中定义的辅助方法ValidIdentifier,从Contact Type Name中删除所有无效的字符,给每个Contact类型创建一个有效的标识符。
生成的输出文件显示在下面的清单中。与生成它的脚本相比,最终结果看起来相当简单,但这有点欺骗性。在ContactType表中添加、删除数据行时,T4模板可以保持不变。实际上,数据库中的项可以完全重新排序,而代码仍能编译。略加修改,这个脚本甚至可以用于一次从许多不同的表中生成枚举类型。
C#
// This code is generated. Please do not edit it directly // If you need to make changes please edit ContactType.tt instead namespace AdventureWorks { public enum ContactType { AccountingManager = 1, AssistantSalesAgent = 2, AssistantSalesRepresentative = 3, CoordinatorForeignMarkets = 4, ExportAdministrator = 5, InternationalMarketingManager = 6, MarketingAssistant = 7, MarketingManager = 8, MarketingRepresentative = 9, OrderAdministrator = 10, Owner = 11, OwnerMarketingAssistant = 12, ProductManager = 13, PurchasingAgent = 14, PurchasingManager = 15, RegionalAccountRepresentative = 16, SalesAgent = 17, SalesAssociate = 18, SalesManager = 19, SalesRepresentative = 20, } }
VB
' This code is generated. Please do not edit it directly ' If you need to make changes please edit ContactType.tt instead Namespace AdventureWorks Enum ContactType AccountingManager = 1 AssistantSalesAgent = 2 AssistantSalesRepresentative = 3 CoordinatorForeignMarkets = 4 ExportAdministrator = 5 InternationalMarketingManager = 6 MarketingAssistant = 7 MarketingManager = 8 MarketingRepresentative = 9 OrderAdministrator = 10 Owner = 11 OwnerMarketingAssistant = 12 ProductManager = 13 PurchasingAgent = 14 PurchasingManager = 15 RegionalAccountRepresentative = 16 SalesAgent = 17 SalesAssociate = 18 SalesManager = 19 SalesRepresentative = 20 End Enum End Namespace