三、约定
这里写的东东都是从CodeSmith自带的帮助文档中FAQ里学到的东东
1.如何在模板中添加注释
CodeSmith:
<%-- Comments --%>
VB.NET:
<%-- 'Comments --%>
C#:
<%-- // Comments --%>
<%-- /* Comments */ --%>
2.创建一个可以下拉选择的属性
首先定义一个枚举类型的变量,然后将属性的类型设置为枚举型
CS_Identity_Example.cst文件源代码
1
<%
@ Property Name
=
"
CollectionType
"
Type
=
"
CollectionTypeEnum
"
Category
=
"
Collection
"
Description
=
"
Type of collection
"
%>
2
3
<
script runat
=
"
tempate
"
>
4
public enum CollectionTypeEnum
5
{
6
Vector,
7
HashTable,
8
SortedList
9
}
10
script
>
3.解决ASP.NET中标签<%重复问题
先将ASP.NET中使用的这个重复标签写成<%%,避免在生成代码时由于是标签重复引起的编译错误或生成错误。
4.如何声明一个常量
<
script runat
=
"
template
"
>
private const string MY_CONST
=
"
example
"
;
script
>
5.如何对模板进行调试
如果要调试一个模板,首先要在代码模板里进行声明,然后在你想要进行调试的地方用Debugger.Break()语句设置断点即可。
<%
@ CodeTemplate Language
=
"
C#
"
TargetLanguage
=
"
T-SQL
"
Description
=
"
Debugging your template
"
Debug
=
"
true
"
%>
<%
Debugger.Break();
%>
6.如何将属性设置成选择一个文件夹的路径
[Editor(
typeof
(System.Windows.Forms.Design.FolderNameEditor),
typeof
(System.Drawing.Design.UITypeEditor))]
public
string
OutputDirectory
{
get
{
return
_outputDirectory;}
set
{_outputDirectory
=
value;}
}
7.怎样调用子模板
1
<%
2
foreach
(TableSchema table
in
SourceDatabase.Tables)
3

{
4
OutputSubTemplate(table);
5
}
6
%>
7
<
script runat
=
"
template
"
>
8
private
CodeTemplate _mySubTemplate;
9

10
[Browsable(
false
)]
11
public
CodeTemplate MySubTemplate
12

{
13
get
14
{
15
if (_mySubTemplate == null)
16
{
17
CodeTemplateCompiler compiler = new CodeTemplateCompiler(this.CodeTemplateInfo.DirectoryName + "MySubTemplate.cst");
18
compiler.Compile();
19
if (compiler.Errors.Count == 0)
20
{
21
_mySubTemplate = compiler.CreateInstance();
22
}
23
else
24
{
25
for (int i = 0; i < compiler.Errors.Count; i++)
26
{
27
Response.WriteLine(compiler.Errors[ i].ToString());
28
}
29
}
30
}
31
return _mySubTemplate;
32
}
33
}
34

35
public
void
OutputSubTemplate(TableSchema table)
36

{
37
MySubTemplate.SetProperty("SourceTable", table);
38
MySubTemplate.SetProperty("IncludeDrop", false);
39
MySubTemplate.SetProperty("InsertPrefix", "Insert");
40
MySubTemplate.Render(Response);
41
}
42
script
>
FAQ中给出的例子为生成一个数据库中所有表的更新Update存储过程
SubTemplatesExample.cst文件源代码
1
<%
@ CodeTemplate Language
=
"
C#
"
TargetLanguage
=
"
T-SQL
"
2
Description
=
"
Generates a update stored procedure.
"
%>
3

4
<%
@ Property Name
=
"
SourceDatabase
"
Type
=
"
SchemaExplorer.DatabaseSchema
"
5
Category
=
"
Context
"
6
Description
=
"
Database
"
%>
7

8
<%
@ Assembly Name
=
"
SchemaExplorer
"
%>
9

10
<%
@ Import Namespace
=
"
SchemaExplorer
"
%>
11

12
<%
13
foreach
(TableSchema table
in
SourceDatabase.Tables)
14

{
15
OutputSubTemplate(table);
16
}
17
%>
18

19
<
script runat
=
"
template
"
>
20
private
CodeTemplate _mySubTemplate;
21
22

23
24

25
[Browsable(
false
)]
26
public
CodeTemplate MySubTemplate
27

{
28
get
29
{
30
if (_mySubTemplate == null)
31
{
32
CodeTemplateCompiler compiler = new CodeTemplateCompiler(this.CodeTemplateInfo.DirectoryName + "MySubTemplate.cst");
33
compiler.Compile();
34
35
if (compiler.Errors.Count == 0)
36
{
37
_mySubTemplate = compiler.CreateInstance();
38
}
39
else
40
{
41
for (int i = 0; i < compiler.Errors.Count; i++)
42
{
43
Response.WriteLine(compiler.Errors[ i].ToString());
44
}
45
}
46
}
47
48
return _mySubTemplate;
49
}
50
}
51

52
public
void
OutputSubTemplate(TableSchema table)
53

{
54
MySubTemplate.SetProperty("SourceTable", table);
55
MySubTemplate.SetProperty("IncludeDrop", false);
56
MySubTemplate.SetProperty("InsertPrefix", "Insert");
57
58
MySubTemplate.Render(Response);
59
}
60
script
>
MySubTemplate.cst文件源代码
1
<%
@ CodeTemplate Language
=
"
C#
"
TargetLanguage
=
"
T-SQL
"
2
Description
=
"
Generates a update stored procedure.
"
%>
3

4
<%
@ Property Name
=
"
SourceTable
"
Type
=
"
SchemaExplorer.TableSchema
"
5
Category
=
"
Context
"
6
Description
=
"
Table that the stored procedures should be based on.
"
%>
7

8
<%
@ Assembly Name
=
"
SchemaExplorer
"
%>
9

10
<%
@ Import Namespace
=
"
SchemaExplorer
"
%>
11
12
13
<
script runat
=
"
template
"
>
14
public
string
GetSqlParameterStatement(ColumnSchema column)
15

{
16
string param = "@" + column.Name + " " + column.NativeType;
17
18
switch (column.DataType)
19
{
20
case DbType.Decimal:
21
{
22
param += "(" + column.Precision + ", " + column.Scale + ")";
23
break;
24
}
25
default:
26
{
27
if (column.Size > 0)
28
{
29
param += "(" + column.Size + ")";
30
}
31
break;
32
}
33
}
34
35
return param;
36
}
37
script
>
38

39
-----------------------------------------------------------------
40
--
Date Created:
<%=
DateTime.Now.ToLongDateString()
%>
41
--
Created By: Generated by CodeSmith
42
-----------------------------------------------------------------
43

44
CREATE PROCEDURE dbo.Update
<%=
SourceTable.Name
%>
45

<%
for
(
int
i
=
0
; i
<
SourceTable.Columns.Count; i
++
)
{ %>
46
<%= GetSqlParameterStatement(SourceTable.Columns[i]) %><% if (i < SourceTable.Columns.Count - 1)
{ %>,<% } %>
47
<% }
%>
48
AS
49

50
UPDATE [
<%=
SourceTable.Name
%>
] SET
51

<%
for
(
int
i
=
0
; i
<
SourceTable.NonPrimaryKeyColumns.Count; i
++
)
{ %>
52
[<%= SourceTable.NonPrimaryKeyColumns[i].Name %>] = @<%= SourceTable.NonPrimaryKeyColumns[i].Name %><% if (i < SourceTable.NonPrimaryKeyColumns.Count - 1)
{ %>,<% } %>
53
<% }
%>
54
WHERE
55

<%
for
(
int
i
=
0
; i
<
SourceTable.PrimaryKey.MemberColumns.Count; i
++
)
{ %>
56
<% if (i > 0)
{ %>AND <% } %>
57
[<%= SourceTable.PrimaryKey.MemberColumns[i].Name %>] = @<%= SourceTable.PrimaryKey.MemberColumns[i].Name %>
58
<% }
%>
8.在加载模板时默认加载的命名空间Namespaces和组件Assemblies
组件:mscorlib, System, System.Xml, System.Data, System.Drawing, Microsoft.VisualBasic, System.Windows.Forms, CodeSmith.Engine
命名空间:System, System.Data, System.Diagnostics, System.ComponentModel, Microsoft.VisualBasic, CodeSmith.Engine
9.使用SchemaExplorer能否确定一个字段(Field)是标识字段(主键,Identity Field)
在字段的扩展属性集合中包含一个叫“CS_IsIdentity”的属性,如果这个属性的值为true,则表名当前字段为一个标识字段
1
Identity Field
=
<%
foreach
(ColumnSchema cs
in
SourceTable.Columns) {
2
if
( ((
bool
)cs.ExtendedProperties[
"
CS_IsIdentity
"
].Value)
==
true
)
3
{
4
Response.Write(cs.Name);
5
}
6
}
7
%>
1
<%
@ CodeTemplate Language
=
"
C#
"
TargetLanguage
=
"
T-SQL
"
2
Description
=
"
Identifies the identity field of a table
"
%>
3
4
<%
@ Property Name
=
"
SourceTable
"
Type
=
"
SchemaExplorer.TableSchema
"
5
Category
=
"
Context
"
6
Description
=
"
Table to target.
"
%>
7
8
<%
@ Assembly Name
=
"
SchemaExplorer
"
%>
9
10
<%
@ Import Namespace
=
"
SchemaExplorer
"
%>
11
12
13
14
Identity Field
=
<%
foreach
(ColumnSchema cs
in
SourceTable.Columns) {
15
if
( ((
bool
)cs.ExtendedProperties[
"
CS_IsIdentity
"
].Value)
==
true
)
16
{
17
Response.Write(cs.Name);
18
}
19
}
20
%>
10.如何确定一个字段的默认值(各人认为翻译成如何知道一个字段有默认值并且默认值是什么)
在字段的扩展属性集合中包含一个叫“CS_Default”的属性
1
<%
2
foreach
(ColumnSchema cs
in
SourceTable.Columns) {
3
if
(cs.ExtendedProperties[
"
CS_Default
"
]
!=
null
)
4
{
5
Response.WriteLine(cs.ExtendedProperties[
"
CS_Default
"
].Value);
6
}
7
}
8
%>
11.如何使用SchemaExplorer得到存储过程的输入输出参数
使用CodeSmith提供的CommandSchema对象,它包含需要的输入输出参数集合
1
Input Parameters:
2
<%
foreach
(ParameterSchema ps
in
SourceProcedure.AllInputParameters)
3
{
4
Response.Write(ps.Name);
5
Response.Write(
"
/n
"
);
6
}
7
%>
8
9
10
Output Parameters:
11
<%
foreach
(ParameterSchema ps
in
SourceProcedure.AllOutputParameters)
12
{
13
Response.Write(ps.Name);
14
Response.Write(
"
/n
"
);
15
}
16
%>
InputOutputParameterExample.cst文件源代码
1
<%
@ CodeTemplate Language
=
"
C#
"
TargetLanguage
=
"
T-SQL
"
2
Description
=
"
Generates a update stored procedure.
"
%>
3
4
<%
@ Property Name
=
"
SourceProcedure
"
Type
=
"
SchemaExplorer.CommandSchema
"
5
Category
=
"
Context
"
6
Description
=
"
The stored procedure to examine
"
%>
7
8
<%
@ Assembly Name
=
"
SchemaExplorer
"
%>
9
10
<%
@ Import Namespace
=
"
SchemaExplorer
"
%>
11
12
Input Parameters:
13
<%
foreach
(ParameterSchema ps
in
SourceProcedure.AllInputParameters)
14
{
15
Response.Write(ps.Name);
16
Response.Write(
"
/n
"
);
17
}
18
%>
19
20
21
Output Parameters:
22
<%
foreach
(ParameterSchema ps
in
SourceProcedure.AllOutputParameters)
23
{
24
Response.Write(ps.Name);
25
Response.Write(
"
/n
"
);
26
}
27
%>
四、语法与标签
一下内容介绍在CodeSmith中使用的语法和标签的参考。
CodeSmith模板语法参考
本文的目的是在编写一个CodeSmith模板时遇到的各种类型的变量和对象提供参考。本文的目的不是要介绍CodeSmith,如果您想快速了解CodeSmith请查看我翻译的CodeSmith基础(一)和CodeSmith基础(二)。
标签
标签一般出现在模板的头部,被用做设置许多不同的属性。
代码模板的声明(CodeTemplate Directive)
这个是模板中唯一必须的声明,包含一些模板特殊的属性,包含模板使用的语言、生成的语言和一些对于模板的描述。
例:
<
%@ CodeTemplate
Language
="C#"
TargetLanguage
="C#"
Description
="Generates a class."
%
>
参数的介绍:
Language:在开发编写模板时使用的语言,例如C#,VB.NET,Jscript等。
TargetLanguage:只是对模板代码的一个分类,不会影响生成的代码语言。是模板的一个属性,说明模板要基于那种语言生成相应的代码。例如你可以用CodeSmith从任何一种语言生成C#代码。
Description:对于模板的一些说明信息,在CodeSmith Explorer中选中该模板时会显示这里的信息。
Inherits:所有CodeSmith模板默认继承自CodeSmith.Engine.CodeTemplate,这个类提供模板使用的一些基本功能,像ASP.NET页面的Page类,这些被继承的类的属性可以被修改,但是这些新的类也必须继承CodeSmith.Engine.CodeTemplate。CodeSmith也同样可以找到这个类,当然你要引入一个组件包含这个类。
Src:在某些方面Src和继承Inherits比较相似,它们都允许你从其他的类包含一些功能进模板。这两个属性的区别是,Src可以让类与你的模板被动态编译,而Inherits仅允许你提供一个已经编译好的类或组件。
Debug:可以确定是否在模板中可以包含调试符号。如果将这个属性设置为True,则可以使用System.Diagnostics.Debugger.Break()方法来设置断点。
LinePragmas:设置为True,模板的错误将被指向到模板的源代码。设置为False,模板的错误将被指向到编译的源代码。
属性的声明(Property Directive)
属性被用做在模板运行时声明一个使用的参数,例:
<
%@ Property
Name
="ClassName"
Type
="String"
Default
="Class1"
Category
="Context"
Description
="The name of the class to generate"
Optional
="true"
%
>
属性参数的介绍:
Name:模版使用的参数的名称。
Type:参数类型可以是任何.NET有效的数据类型,例如简单的String类型或者是CodeSmith的SchemaExplorer.DatabaseSchema类型。注意,类型必须是基类库的类型,例如用String或者Int32代替string和int。
Default:设置默认值。
Category:用来说明这个属性在CodeSmith Explorer的属性面板中显示成什么类型,例如下拉选择、直接输入等。
Description:在属性面板中对于这个属性的描述。
Optional:设置这个属性是否是必须的,设置为True表明这个参数值可有可无,设置为False则这个参数必须有值。
Editor:表明在属性面板中输入这个属性的值时使用何种GUI(图形界面编辑器)编辑器。
EditorBase:编辑器使用的基本类型,如果没有被说明,UITypeEditor为默认编辑器。
Serializer:这块我的水平不太会犯疑:)The serializer parameter specifies the IPropertySerializer type to use when serializing the properties values. This is equivalent to using a [PropertySerializerAttribute].
XML属性声明(XmlProperty Directive)
例:属性的参数:
Name:名称。
Schema:这个参数用来指定一个XSD文件,创建一个强类型对象模型。如果这个计划被指定,编译器会尝试分析这个XSD文件并为这个计划生成一个强类型对象模型,这样可以在模版中使用强类型和智能与XML协同工作。如果这个计划没有被设定,这个参数将为XmlDocument类型并且将使用XML DOM去导航到一个XML内容并生成代码。
Category:在CodeSmith属性面板中的类别。
Description:描述。
Optional:这个参数是否是必须的,如果设置为True,则参数不是必须的,反之False则为必须的。在设置为False时,如果用户没有提供参数则CodeSmith不能继续运行。
注册的声明(Register Directive)
这个属性通常被用作引入另一个模版文件并与当前的模版文件同时被编译。这是一种使用子模版的交互方法。
例:
<
%@ XmlProperty
Name
="EntityMap"
Schema
="EntityMap.xsd"
Optional
="False"
Category
="Context"
Description
="EntityMap XML file to base the output on."
%
>
XML
<
%@ Register
Name
="MySubTemplate"
Template
="MySubTemplate.cst"
MergeProperties
="True"
ExcludeProperties
="SomeExcludedPropertyName,SomeProperties*"
%
>
模版一旦被注册,就可以建立一个模版的实例,然后象这样设置它的属性:
1
<
script runat
=
"
template
"
>
2
public
void
OutputSubTemplate()
3
{
4
MySubTemplate mySubTemplate
=
new
MySubTemplate();
5
6
//
set an individual properties value.
7
mySubTemplate.SomeExcludedPropertyName
=
"
SomeValue
"
;
8
9
//
copy all properties with matching name and type to the sub template instance.
10
this
.CopyPropertiesTo(mySubTemplate);
11
12
//
render the template to the current templates Response object.
13
mySubTemplate.Render(
this
.Response);
14
15
//
render the template to a file.
16
mySubTemplate.RenderToFile(
"
C:/SomeFile.txt
"
);
17
}
18
script
>
注册的参数:
Name:代表被引入的模版的名称。它可以被用作创建一个模版的实例。
Template:被引入模版文件的相对路径,它可以与当前的模版一起被动态的编译。
MergeProperties:设置成True时,所有被引用的面板的属性将被动态的添加到当前模版中。
ExcludePorperties:当使用MergeProperties时,你可能不需要某些属性被添加到当前模版中。将不需要的属性以逗号分隔放在这里,*号可以被用作通配符使用。
组件的声明(Assembly Directive)
用作在模版中引用一个外部部组件,或者包含一个编译好的源文件。
例:或
<
%@ Assembly
Name
="SchemaExplorer"
%
>
<
%@ Assembly
Src
="MySourceFile.cs"
%
>
CodeSmith自动加载一些不同的组件:System, System.Diagnostics, System.ComponentModel, Microsoft.VisualBasic, CodeSmith.Engine
组件的参数:
Name:需要引用组件的名称,组建必须存在于Global Assembly Cache,与CodeSmith在同一路径下或与模版文件在同一路径下。
Src:要包含文件的相对路径。
引入的声明(Import Directive)
在模版中引入一个命名空间,这个与VB.NET中的Imports和C#中的using相同。
例:引入的参数:
NameSpace:被引入的命名空间的名字。记住同时必须要加载包含这个命名空间的相应组件,除非这个组件是被默认加载的。
<
%@ Import
Namespace
="SchemaExplorer"
%
>