codesmith 入门介绍【转载】 -凯发k8网页登录
最近两天自己写了个简单的orm框架,非常的easy,但是没有相应的代码生成工具,于是就很杯具了!
于是乎,花费了一天的时间学习并写了一个codesmith可以使用的模板。在此记录下codesmith的学习笔记。
所用工具: codesmith professional v5.1.3.8510,代码示例全部是以c#为例。
codesmith默认是不支持中文的,那么我们必须要先设置使其支持中文显示,保存。并且要能够在生成文件中支持中文。
- [tools->options...->studio->editor->enable
unicode]将这个选项勾上,那么codesmith就可以显示和保存中文了。
- 在你的模板的最前面的一句话,c#为例:
<%@ codetemplate
targetlanguage="text" src="" inherits="" debug="false" compilerversion="v3.5"
description="template description here." %>
中加入responseencoding="utf-8" 的标签。将会使得生成的文件也支持中文。
- [tools->options...->studio->editor->convert tab
to]去掉这个的勾选,就是不使用空格来替换tab。
codesmith的模板分为六个区域:模板说明区域,属性设置区域,注册模板区域,引用声明区域,模板区域,函数区域。
(一) 模板说明区域,只有一句话:
<%@ codetemplate
responseencoding="utf-8" targetlanguage="text" src="" inherits="" debug="false"
compilerversion="v3.5" description="这里是模板说明" %>
(二) 属性设置区域
你模板需要那些外接参数,都可以写在这里。当然还有一些其他的参数需要些在函数区域,在后面我们再来描述。
1) string类型参数声明:
<%@ property default="aaa"
optional="true" category="输入参数" description="这是一个字符串型的参数" %>
2) bool类型参数声明:
<%@ property
default="true" optional="false" category="输入参数" description="这是一个布朗型的参数"
%>
3) databaseschema类型参数声明:
<%@ property
category="context" description="这是一个数据库" %>
4) tableschemacollection类型参数声明:
<%@ property
category="context" description="这是一个数据表集合" %>
5) tableschema类型参数声明:
<%@ property
category="context" description="这是一个数据表" %>
(三) 注册模板区域
在你的模板中可以调用其他的模板用于生成,当然,你调用的模板所需要的参数你都必须给出。注册代码如下:
<%@ register
template="b.cst" mergeproperties="false" excludeproperties="" %>
这就是将b模板注册到a模板中。
(四) 引用声明区域
在这里要将我们使用到了的应用集都在这里写出来,如果使用到数据库就一定要添加下面的两个。
<%@ assembly
%>
<%@ import
namespace="schemaexplorer" %>
要自己控制输出文件的话就需要添加:<%@ import
namespace="system.io" %>
(五) 模板区域
这里就是我们控制要输出的文件或者界面的内容。
直接输出值为<%= thisisstring
%>
调用代码为<% if (thisisbool) {
%>a<% } %> 如果thisisbool为true则输出a。
(六) 函数区域
在这里我们可以定义我们自己的函数,用于一些复杂的组合、代码的重用等。代码格式和c#完全一样。
a. 直接输出
在模板区域直接输入文本,就会直接输出的output里面了。
b. 变量输出
例如输出thisisstring的变量值:<%=
thisisstring %>
再例如输出thisistable的名字:<%= thisistable.name %>
c. 调用函数
例如,如果输入的thisisbool为true就输出a字符。
<% if (thisisbool) {
%>a<% } %>
d. 调用模板
这里我们将在a模板内调用并显示b模板。每个模板都有一个response来存储模板输出的。模板显示是调用render()方法来完成的。
<% for(int i = 0; i <
thisistablelist.count; i )
{
b b = new b();
b.thisistable =
thisistablelist[i];
b.render(this.response);
} %>
e. 遍历database或tablecollection内的表
这里我们可以使用for或者foreach做循环,为了通用性例子全部使用for做循环。
遍历thisisdatabase并输出表名
<% for (int t = 0; t <
thisisdatabase.tables.count; t ) { %>
<%=
thisisdatabase.tables[t].name %>
<% } %>
f. 遍历table的列
遍历thisistable的列并且生成类似如下格式的语句:
//数据库类型:dbtype.int
private int _id;
这里调用了一个方法datatype2csharptype(system.data.dbtype dbtype)在后面将会讲到。
<% for (int c = 0; c <
thisistable.columns.count; c ) { %>
//数据库类型:dbtype.<%=
datatype2csharptype(thisistable.columns[c].datatype) %>
private <%=
datatype2csharptype(thisistable.columns[c].datatype) %> _<%=
thisistable.columns[c].name %>;
<% } %>
输出结果:
//数据库类型:dbtype.int
private int
_id;
//数据库类型:dbtype.int
private int
_classid;
//数据库类型:dbtype.string
private string
_studentname;
g. 遍历table的pk
<% for (int c = 0; c <
thisistable.primarykey.membercolumns.count; c ) { %>
主键<%= c %>:<%=
thisistable.primarykey.name %>
<%=
thisistable.primarykey.table.name %>.<%=
thisistable.primarykey.membercolumns[c].name %>
<% } %>
输出结果 :
主键0:pk_student
student.id
h. 遍历table的fk(table自己是外键表<即table为明细表>)
这里说明下,下面的代码仅仅只是对fk里面的列是一对一的有效,如果是多对多的fk需要修改下面的0的地方为循环即可。
<% for (int c = 0; c <
thisistable.foreignkeys.count; c ) { %>
外键<%= c %>:<%=
thisistable.foreignkeys[c].name %>
外键<%= c
%>对应的列
<% for (int i = 0; i
< thisistable.foreignkeys[c].primarykeymembercolumns.count; i ) {
%>
<%=
thisistable.foreignkeys[c].foreignkeytable.name %>.<%=
thisistable.foreignkeys[c].foreignkeymembercolumns[0].name %> <——来自于
<%= thisistable.foreignkeys[c].primarykeytable.name %>.<%=
thisistable.foreignkeys[c].primarykeymembercolumns[0].name %>
<% } %>
<% } %>
输出结果:
外键0:fk_student_class
外键0对应的列
i. 遍历table的fk(table自己是主键表<即table为父表>)
<% for (int c = 0; c <
thisistable.primarykeys.count; c ) { %>
其他表外键<%= c %>:<%=
thisistable.primarykeys[c].name %>
其他表外键<%= c
%>对应的列:
<% for (int i = 0; i
< thisistable.primarykeys[c].primarykeymembercolumns.count; i ) {
%>
<%=
thisistable.primarykeys[c].primarykeytable.name %>.<%=
thisistable.primarykeys[c].primarykeymembercolumns[0].name %> 作用于——>
<%= thisistable.primarykeys[c].foreignkeytable.name %>.<%=
thisistable.primarykeys[c].foreignkeymembercolumns[0].name %>
<% } %>
<% } %>
输出结果:
其他表外键0:fk_examscore_student
其他表外键0对应的列:
student.id 作用于——>
examscore.studentid
之前我们提到过,有些参数必须要写在函数区域中。当然这些参数就是需要有一些其他组件支持的参数了,比如弹出一个窗口选择文件,或者弹出一个选择文件夹的窗体,用于输入的参数。
1) 添加一个选择目录的输入参数
下面我们就是定义了一个输入参数outputdirectory,在运行的输入参数界面,点击这个参数的输入框就会弹出一个选择目录的窗口。
private string
templateoutputdirectory = "";
[editor(typeof(system.windows.forms.design.foldernameeditor),
typeof(system.drawing.design.uitypeeditor))]
[optional,
notchecked]
[category("outputinfo")]
[description("输出结果的目录。")]
[defaultvalue("")]
public string
outputdirectory
{
get
{
if
(string.isnullorempty(templateoutputdirectory))
{
return
"c:\\" (thisisdatabase!= null ? thisisdatabase.name : "output");
}
else
{
return
templateoutputdirectory;
}
}
set
{
if
(value.endswith("\\")) value = value.substring(0, value.length - 1);
templateoutputdirectory = value;
}
}
2) 添加一个选择文件的输入参数
下面我们就是定义了一个输入参数outputfile,在运行的输入参数界面,点击这个参数的输入框就会弹出一个选择文件的窗口。
private string
templateoutputfile;
[editor(typeof(system.windows.forms.design.filenameeditor),
typeof(system.drawing.design.uitypeeditor))]
[optional,
notchecked]
[category("outputinfo")]
[description("输出文件")]
[defaultvalue("")]
public string
outputfile
{
get
{
if
(string.isnullorempty(templateoutputfile))
{
return
"c:\\" (thisisdatabase != null ? thisisdatabase.name ".cs" :
"output.cs");
}
else
{
return
templateoutputfile;
}
}
set
{
templateoutputfile = value;
}
}
3) 将数据库类型转化为c#类型的函数
输入dbtype的类型转化后输出c#的类型的字符串。这个函数很常用到。
public string datatype2csharptype(system.data.dbtype
dbtype)
{
switch
(dbtype)
{
case
dbtype.ansistring:
return
"string";
case
dbtype.ansistringfixedlength:
return
"string";
case
dbtype.binary:
return
"byte[]";
case
dbtype.boolean:
return
"bool";
case
dbtype.byte:
return
"byte";
case
dbtype.currency:
return
"decimal";
case
dbtype.date:
return
"datetime";
case
dbtype.datetime:
return
"datetime";
case
dbtype.datetime2:
return
"datetime";
case
dbtype.datetimeoffset:
return
"datetime";
case
dbtype.decimal:
return
"decimal";
case
dbtype.double:
return
"double";
case
dbtype.guid:
return
"guid";
case
dbtype.int16:
return
"short";
case
dbtype.int32:
return
"int";
case
dbtype.int64:
return
"long";
case
dbtype.object:
return
"object";
case
dbtype.sbyte:
return
"sbyte";
case
dbtype.single:
return
"float";
case
dbtype.string:
return
"string";
case
dbtype.stringfixedlength:
return
"string";
case
dbtype.time:
return
"datetime";
case
dbtype.uint16:
return
"ushort";
case
dbtype.uint32:
return
"uint";
case
dbtype.uint64:
return
"ulong";
case
dbtype.varnumeric:
return
"decimal";
case
dbtype.xml:
return
"string";
default:
return
"object";
}
}
4) 获取数据库类型的字段在c#中的默认值
输入dbtype的类型转化后输出c#的类型的默认值。这个函数和上面那个差不多,只是有些时候设置了值后希望给个默认值而已。
public string
datatypedefaultvalue(system.data.dbtype dbtype)
{
switch
(dbtype)
{
case
dbtype.ansistring:
return
"string.empty";
case
dbtype.ansistringfixedlength:
return
"string.empty";
case
dbtype.binary: //answer modified was just 0
return "new
byte[] {}";
case
dbtype.boolean:
return
"false";
case dbtype.byte:
//answer modified was just 0
return
"(byte)0";
case
dbtype.currency:
return
"0";
case
dbtype.date:
return
"datetime.minvalue";
case
dbtype.datetime:
return
"datetime.minvalue";
case
dbtype.datetime2:
return
"datetime.minvalue";
case
dbtype.datetimeoffset:
return
"datetime.minvalue";
case
dbtype.decimal:
return
"0.0m";
case
dbtype.double:
return
"0.0f";
case
dbtype.guid:
return
"guid.empty";
case
dbtype.int16:
return
"(short)0";
case
dbtype.int32:
return
"(int)0";
case
dbtype.int64:
return
"(long)0";
case
dbtype.object:
return "new
object()";
case
dbtype.sbyte:
return
"(sbyte)0";
case
dbtype.single:
return
"0f";
case
dbtype.string:
return
"string.empty";
case
dbtype.stringfixedlength:
return
"string.empty";
case
dbtype.time:
return "new
datetime(1900,1,1,0,0,0,0)"; //return "datetime.maxvalue";
case
dbtype.uint16:
return
"(ushort)0";
case
dbtype.uint32:
return
"(uint)0";
case
dbtype.uint64:
return
"(ulong)0";
case
dbtype.varnumeric:
return
"(decimal)0";
case
dbtype.xml:
return
"string.empty";
default:
return
"null";
}
}
5) 文件输出函数
当然了,做了这么多的工作,最后肯定是希望输出成文件咯,在前面我们已经说过了,对于输出的结果是调用render()方法,那么我们只需要在render()方法里面输出文件就可以了。
public override void render(textwriter writer)
{
if
(!directory.exists(outputdirectory))
directory.createdirectory(outputdirectory);
streamwriter basefile
= new streamwriter(outputfile, false);
base.render(writer);
basefile.close();
}
当然了,我们也可以再嵌入的其他模板里面调用这些输出的方法,从而达到输出多个文件的目的,这里就不再详细的写代码了。
另附上完整的b的代码:
<%@ codetemplate responseencoding="utf-8"
targetlanguage="text" src="" inherits="" debug="false" compilerversion="v3.5"
description="这里是模板说明" %>
<%@ property
category="context" description="这是一个数据表" %>
<%@ assembly
%>
<%@ import
namespace="schemaexplorer" %>
数据表名称:<%= thisistable.name
%>
<% for (int c = 0; c <
thisistable.primarykey.membercolumns.count; c ) { %>
主键<%= c %>:<%=
thisistable.primarykey.name %>
<%=
thisistable.primarykey.table.name %>.<%=
thisistable.primarykey.membercolumns[c].name %>
<% } %>
<% for (int c = 0; c <
thisistable.foreignkeys.count; c ) { %>
外键<%= c %>:<%=
thisistable.foreignkeys[c].name %>
外键<%= c
%>对应的列
<% for (int i = 0; i
< thisistable.foreignkeys[c].primarykeymembercolumns.count; i ) {
%>
<%=
thisistable.foreignkeys[c].foreignkeytable.name %>.<%=
thisistable.foreignkeys[c].foreignkeymembercolumns[0].name %> <——来自于
<%= thisistable.foreignkeys[c].primarykeytable.name %>.<%=
thisistable.foreignkeys[c].primarykeymembercolumns[0].name %>
<% } %>
<% } %>
<% for (int c = 0; c <
thisistable.primarykeys.count; c ) { %>
其他表外键<%= c %>:<%=
thisistable.primarykeys[c].name %>
其他表外键<%= c
%>对应的列:
<% for (int i = 0; i
< thisistable.primarykeys[c].primarykeymembercolumns.count; i ) {
%>
<%=
thisistable.primarykeys[c].primarykeytable.name %>.<%=
thisistable.primarykeys[c].primarykeymembercolumns[0].name %> 作用于——>
<%= thisistable.primarykeys[c].foreignkeytable.name %>.<%=
thisistable.primarykeys[c].foreignkeymembercolumns[0].name %>
<% } %>
<% } %>
数据表select语句:private const
string selectstring = @"
select
<% for
(int c = 0; c < thisistable.columns.count; c ) { %>
[<%=
thisistable.columns[c].name %>]<% if (c < thisistable.columns.count -
1) { %>,<% } %>
<% }
%>
from [<%=
thisistable.name %>] where 1 = 1 ";
各字段数据类型:
<% for (int c = 0; c <
thisistable.columns.count; c ) { %>
//数据库类型:dbtype.<%=
datatype2csharptype(thisistable.columns[c].datatype) %>
private <%=
datatype2csharptype(thisistable.columns[c].datatype) %> _<%=
thisistable.columns[c].name %>;
<% } %>
posted on 2013-06-15 15:31
sanmao 阅读(989)
评论(0) 编辑 收藏