在开发过程种,很多时候我们会写很多相似度很高的代码,书写这些代码是有规律的,比如我们会根据数据表生成实体类,就像EF那样,会从表中自动生成实体类,如果我们写一个应用程序,读取数据库,然后生成一个.cs类文件,这个相对简单,如果在VS中能解决这个问题,不用单跑一个执行程序就happy了,那T4就是来干这件事的。T4是Text Template Transformation Toolkit全称,不作更多的解释,VS中的T4详见https://msdn.microsoft.com/zh-cn/library/bb126445.aspx。
简单看一个例子,就是把数据的表生成对应的实体类,在项目中创建一个“运行时文本模版”,扩展名是.tt,其实.tt中的代码是标准的C#代码,并键时.tt可以在设计时生成.cs文件,也可以运行时生成,本例是设计时生成,代码如下:
<#@ template debug="false" hostspecific="true" language="C#" #><#@ assembly name="System.Core" #><#@ assembly name="System.Data" #><#@ assembly name="System.Configuration" #><#@ assembly name="System.Xml" #><#@ import namespace="System.Linq" #><#@ import namespace="System.Text" #><#@ import namespace="System.Collections.Generic" #><#@ import namespace="System.Data" #><#@ import namespace="System.Data.SqlClient" #><#@ import namespace="System.Configuration" #><#@ import namespace="System.Xml" #><#@ output extension=".txt" #> <#//数据库连接字符串 var constr="server=.;database=testdb;uid=sa;pwd=gsw123;"; //遍历实体类并生成 foreach (var clas in BuildClass(constr)) { WriteFile(clas.Key,BuildContent(clas.Value)); AddFileToProject(clas.Key); }#>生成实体类成功! <#+ //组装实体类和它的命名空间 string BuildContent(string content) { return @" /***************************** *作者:桂素伟 *时间:"+DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")+@" *说明:按照数据库表自动生成的类 ******************************/ using System; using System.Text; namespace "+Host.ResolveAssemblyReference("$(ProjectName)")+@" { "+ content +@" } "; } //把生成的实体类文件添加到当前项目中 public void AddFileToProject(string className) { //获取当前项目的名称 var proName=Host.ResolveAssemblyReference("$(ProjectName)")+".csproj"; XmlDocument xmlDoc = new XmlDocument(); xmlDoc.LoadXml(System.IO.File.ReadAllText(Host.ResolveAssemblyReference("$(ProjectDir)")+@"\"+proName,Encoding.Default)); XmlNode root = xmlDoc.DocumentElement; if( !root.InnerXml.Contains(@"Include=""" + className + @".cs""")) { root.InnerXml += @"<ItemGroup><Compile Include="""+className+@".cs""></Compile></ItemGroup>"; xmlDoc.Save(Host.ResolveAssemblyReference("$(ProjectDir)")+@"\"+proName); } } //生成实体类文件 public void WriteFile(string className,string content) { var writer = new System.IO.StreamWriter(Host.ResolveAssemblyReference("$(ProjectDir)")+@"\"+className + ".cs", false, Encoding.Default); writer.Write(content); writer.Flush(); writer.Close(); } //从数据库获取实体类名和实体类源码 public Dictionary<string,string> BuildClass(string constr) { using (var con = new System.Data.SqlClient.SqlConnection(constr)) { var cmd = new System.Data.SqlClient.SqlCommand(); cmd.CommandText = "select name from sys.tables WHERE name!='sysdiagrams' AND name!='__MigrationHistory'"; cmd.Connection = con; con.Open(); var dr = cmd.ExecuteReader(); var dt = new DataTable(); dt.Load(dr); dr.Close(); var dic =new Dictionary<string, string>(); foreach (DataRow row in dt.Rows) { cmd.CommandText = string.Format(@"select COLUMN_NAME,DATA_TYPE,CHARACTER_MAXIMUM_LENGTH,IS_NULLABLE from information_schema.columns WHERE TABLE_NAME = '{0}'", row["name"].ToString()); var fielddr = cmd.ExecuteReader(); var fieldTable = new DataTable(); fieldTable.Load(fielddr); fielddr.Close(); dic.Add(row["name"].ToString(), CreateClass(row["name"].ToString(), fieldTable)); } return dic; } } public string CreateClass(string className, DataTable fields) { var csBuilder = new StringBuilder("\r\n"); csBuilder.AppendLine(string.Format(@" public class {0}", className)); csBuilder.AppendLine(@" {"); foreach (DataRow row in fields.Rows) { csBuilder.AppendLine(CreateProperty(row)); } csBuilder.AppendLine(@" }"); return csBuilder.ToString(); } //生成属性 public string CreateProperty(DataRow row) { var dic = new Dictionary<string, string>(); dic.Add("nvarchar", "string"); dic.Add("varchar", "string"); dic.Add("char", "string"); dic.Add("text", "string"); dic.Add("int", "string"); dic.Add("money", "decimal"); dic.Add("float", "float"); dic.Add("bit", "bool"); var csBuilder = new StringBuilder(); csBuilder.AppendLine(string.Format(@" public {0} {1}", dic[row["DATA_TYPE"].ToString().ToLower()], row["COLUMN_NAME"].ToString())); csBuilder.AppendLine(@" {"); csBuilder.AppendLine(string.Format(@" get;")); csBuilder.AppendLine(string.Format(@" set;")); csBuilder.AppendLine(@" }"); return csBuilder.ToString(); } #>