本文转自:http://www.cnblogs.com/sorex/archive/2009/12/24/1631533.html

〇、            前言

最近两天自己写了个简单的ORM框架,非常的Easy,但是没有相应的代码生成工具,于是就很杯具了!

于是乎,花费了一天的时间学习并写了一个CodeSmith可以使用的模板。在此记录下CodeSmith的学习笔记。

所用工具: CodeSmith Professional v5.1.3.8510,代码示例全部是以C#为例。

一、            工具设置

CodeSmith默认是不支持中文的,那么我们必须要先设置使其支持中文显示,保存。并且要能够在生成文件中支持中文。

  1. [Tools->Options...->Studio->Editor->Enable unicode]将这个选项勾上,那么CodeSmith就可以显示和保存中文了。
  2. 在你的模板的最前面的一句话,C#为例:

<%@ CodeTemplate TargetLanguage="Text" Src="" Inherits="" Debug="False" CompilerVersion="v3.5" Description="Template description here." %>

中加入ResponseEncoding="UTF-8" 的标签。将会使得生成的文件也支持中文。

  1. [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 %>;

<% } %>

<script runat="template">

//将数据库类型转化为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 "TimeSpan";

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";

}

}

</script>

OK,终于写完了,花费了一整天的来写,希望对大家有所帮助!

[转]CodeSmith 基础教程的更多相关文章

  1. matlab基础教程——根据Andrew Ng的machine learning整理

    matlab基础教程--根据Andrew Ng的machine learning整理 基本运算 算数运算 逻辑运算 格式化输出 小数位全局修改 向量和矩阵运算 矩阵操作 申明一个矩阵或向量 快速建立一 ...

  2. <<Bootstrap基础教程>> 新书出手,有心栽花花不开,无心插柳柳成荫

    并非闲的蛋疼,做技术也经常喜欢蛋疼,纠结于各种技术,各种需求变更,还有一个很苦恼的就是UI总是那么不尽人意.前不久自己开源了自己做了多年的仓储项目(开源地址:https://github.com/he ...

  3. Memcache教程 Memcache零基础教程

    Memcache是什么 Memcache是danga.com的一个项目,来分担数据库的压力. 它可以应对任意多个连接,使用非阻塞的网络IO.由于它的工作机制是在内存中开辟一块空间,然后建立一个Hash ...

  4. Selenium IDE 基础教程

    Selenium IDE 基础教程 1.下载安装     a 在火狐浏览其中搜索附件组件,查找 Selenium IDE     b 下载安装,然后重启firefox 2.界面讲解      在菜单- ...

  5. html快速入门(基础教程+资源推荐)

    1.html究竟是什么? 从字面上理解,html是超文本标记语言hyper text mark-up language的首字母缩写,指的是一种通用web页面描述语言,是用来描述我们打开浏览器就能看到的 ...

  6. 转发-UI基础教程 – 原生App切图的那些事儿

    UI基础教程 – 原生App切图的那些事儿 转发:http://www.shejidaren.com/app-ui-cut-and-slice.html 移动APP切图是UI设计必须学会的一项技能,切 ...

  7. 【Unity3D基础教程】给初学者看的Unity教程(四):通过制作Flappy Bird了解Native 2D中的RigidBody2D和Collider2D

    作者:王选易,出处:http://www.cnblogs.com/neverdie/ 欢迎转载,也请保留这段声明.如果你喜欢这篇文章,请点[推荐].谢谢! 引子 在第一篇文章[Unity3D基础教程] ...

  8. oracle基础教程(8)oracle修改字符集

    oracle基础教程(8)oracle修改字符集 1.用dba连接数据库 -->sqlplus / as sysdba 2.查看字符集 -->SELECT parameter, value ...

  9. 改写《python基础教程》中的一个例子

    一.前言 初学python,看<python基础教程>,第20章实现了将文本转化成html的功能.由于本人之前有DIY一个markdown转html的算法,所以对这个例子有兴趣.可仔细一看 ...

随机推荐

  1. 关于时间日期的一些操作--java

    # 原创,转载请留言联系 1.获取当前时间 public static void main(String[] args) { Date d1 = new Date(); System.out.prin ...

  2. python中烦人的锟斤拷(\xef\xbf\xbd)

    首先要知道\xef\xbf\xbd是啥东西 >>> u'\uFFFD'.encode('utf-8') '\xef\xbf\xbd' 由此我们可以知道\xef\xbf\xbd是utf ...

  3. Flask 的系统学习

    详细看地址: http://www.cnblogs.com/wupeiqi/articles/7552008.html 一. 说明 Flask是一个基于Python开发并且依赖jinja2模板和Wer ...

  4. redis之(三)redis的数据类型

    [一]字符串类型(基本数据类型) --->字符串类型是redis的最基本的数据类型 --->能存储任何形式的字符串,(用户邮箱,json化的对象,一张图片) --->一个字符串类型的 ...

  5. Search for a Range——稍微升级版的二分查找

    Given a sorted array of integers, find the starting and ending position of a given target value. You ...

  6. AIOps-一位研发工程师的学习笔记

    https://blog.csdn.net/wxm6614/article/details/80457568

  7. AC日记——NOI2016区间 bzoj 4653

    4653 思路: 线段树,指针滑动: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 1000005 #def ...

  8. WebDriver自动化测试工具(3)---PhantomJS的使用

    PhantomJS是一个基于webkit的javascript API.它使用QtWebKit作为它核心浏览器的功能,使用webkit来编译解释执行JavaScript代码.任何你可以在基于webki ...

  9. H264 帧边界识别简介

    http://blog.csdn.net/wzw88486969/article/details/50364017

  10. java网络通信:HTTP协议 之 Sessions与Cookies

    通过前一篇博客的讲解,我们大体知道了HTTP协议是什么,它有什么组成,以及它的工作原理,那么在HTTP的很多特点中,有一点叫做,无状态,就HTTP是一个无状态的协议,如果需要前面的信息用于处理后边的请 ...