在开发过程种,很多时候我们会写很多相似度很高的代码,书写这些代码是有规律的,比如我们会根据数据表生成实体类,就像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文件,也可以运行时生成,本例是设计时生成,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
<#@ 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();
}
#>
|
本文转自桂素伟51CTO博客,原文链接: http://blog.51cto.com/axzxs/1774815
,如需转载请自行联系原作者