〇、 前言
最近兩天自己寫了個簡單的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 %>;
<% } %>
<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>
http://www.cnblogs.com/sorex/archive/2009/12/24/1631533.html
posted on 2013-06-15 15:31
sanmao 閱讀(1059)
評論(0) 編輯 收藏