在项目中,我们在持久化的时候,通常会使用Model层来封装数据——以便于传输,甚至页面的数据绑定时,也通过了Model:通过反射和遍历页面控件的方式。而当我们表格多的时候,写Model是一件很烦的事情——重复无意义的工作,而且还容易出错。看看你的Model吧,绝大部分都是成员变量的声明和属性的定义。
为什么我们不将这件工作交给一个工具来完成呢?
CodeSmith是个很强大的Code生成工具,可以操作数据库、Collection(.net)集合类型等等,可生成c#、js、vb、HashTable、List、Query、Xml,自成一套语法规则。(Eclipse将这个生成工作集成到它的IDE里面去了,虽然没这么强大,当然,你写好模板还是可以生成java代码的)。它的工作原理很简单:读模板文件、用数据覆盖标记、写文件等等,只不过,它将添加了链接了数据库等功能,直接图形化操作,可设置断点调试,解释执行,方便Debug。
好吧,闲话不多少,我们开始本文的主体部分。
首先,你需要下载CodeSmith,并安装(网上有注册机,本文基于V3.2版本)。打开CodeSmith Studio,新建一个c#模板(菜单栏File->New->c# Template)。如下例:
<%
@ CodeTemplate Language
=
"
C#
"
TargetLanguage
=
"
T-SQL
"
Description
=
"
Generates a update stored procedure.
"
%>
<%
@ Assembly Name
=
"
SchemaExplorer
"
%>
<%
@ Import Namespace
=
"
SchemaExplorer
"
%>
<%
@ Property Name
=
"
SourceTable
"
Type
=
"
SchemaExplorer.TableSchema
"
Category
=
"
Context
"
Description
=
"
Table that the stored procedures should be based on.
"
%>
<%@ Assembly Src="CommonUtility.cs" %>
<%
@ Import Namespace
=
"
Common.Data
"
%>
<
script runat
=
"
template
"
>
CommonUtility rule
=
new
CommonUtility();
</
script
>
using
System;
using
System.Collections;
using
System.Collections.Generic;
using
System.Data;
using
TonkNet.FrameWork.Business.Model;
using
TonkNet.FrameWork.Business.Model.Attributes;
namespace
TonkNet.KBS.Model
{
///
<summary>
///
<%= SourceTable.Name %>
object for TFramework mapped table '
<%= SourceTable.Name %>
'.
///
</summary>
[Serializable]
[Table(
"
<%= SourceTable.Name %>
"
,
"
dbo
"
)]
public
class
<%=
SourceTable.Name
%>
{
<%
for
(
int
i
=
0
; i
<
SourceTable.Columns.Count; i
++
) {
%>
protected
<%=
rule.GetCSharpVariableType(SourceTable.Columns[i])
%>
_
<%=
SourceTable.Columns[i].Name
%>
;
<%
}
%>
public
<%=
SourceTable.Name
%>
() { }
<%
for
(
int
i
=
0
; i
<
SourceTable.Columns.Count; i
++
) {
%>
[Column(
"
<%= SourceTable.Columns[i].Name %>
"
,
<%=
rule.GetCSharpVariableType(SourceTable.Columns[i])
%>
,
<%=
SourceTable.Columns[i].Size
%>
, PrimaryKey
=
<%
if
(SourceTable.PrimaryKey.MemberColumns.Count
==
1
&&
SourceTable.Columns[i].IsPrimaryKeyMember) {
%>
true
<%
}
else
{
%>
false
<%
}
%>
)]
public
string
<%=
rule.GetCamelCaseName(SourceTable.Columns[i].Name)
%>
{
get
{
return
_
<%=
SourceTable.Columns[i].Name
%>
; }
set
{ _
<%=
SourceTable.Columns[i].Name
%>
=
value; }
}
<%
}
%>
}
}
这解释一下前面几行:
1. 第一行指名这是一个C#语言模板。
2. <%@ Assembly Name="SchemaExplorer" %>
<%@ Import Namespace="SchemaExplorer" %>加载使用访问数据库的组建SchmaExplorer
3. 接下来表示变量类型为数据库的表,如果你在选择数据库对象时(后面介绍)时,选择的类型是视图,需要将变量类型Type中的SchemaExplorer.TableSchema修改为SchemaExplorer.ViewSchema。
4. <%@ Assembly Src="CommonUtility.cs" %>表示引入类CommonUtility.cs,如此我们便可以使用c#的方法来处理字符串了(比如,你需要将字段名首字母改为大些,该类的GetCamelCaseName(string)方法实现了。) 注意:CommonUtility.cs类(见附录)需要放到安装根目录下,如果路径不对,会提示你,某个文件下找不到这个类,将它copy进去即可。
5. <script>标签内的部分创建了CommonUtility.cs的类的实例。
模板using上面的部分,属于CodeSmith内部的定义,在生成Code时,不会被添加到文件中来。上面的模板可能有些凌乱,简化一下,大约是这个样子(下面的文件只表示文件的结构,模板不可以修改为它):
using
System;
using
System.Collections;
using
System.Collections.Generic;
using
System.Data;
using
TonkNet.FrameWork.Business.Model;
using
TonkNet.FrameWork.Business.Model.Attributes;
namespace
TonkNet.KBS.Model
{
///
<summary>
///
#table.name# object for TFramework mapped table '#table.name#'.
///
</summary>
[Serializable]
[Table(
"
#table.name#
"
,
"
dbo
"
)]
public
class
#table.name#
{
//
循环取table里的字段名,来声明成员变量 CodeSmith里面<%=%>内为代码块(或数据、或函数)
protected
#table.column[i].type# _#table.column[i].name#;
//
循环去table的字段,来定义属性
public
#table.column[i].name#() { }
[Column(
"
#table.column[i].name#
"
, #table.column[i].type#, #table.column[i].size#, PrimaryKey
=
#table.column[i].name#.IsPrimaryKeyMember)
true
else
false
public
string
#table.column[i].name#
{
get
{
return
_#table.column[i].name#; }
set
{ #table.column[i].name#
=
value; }
}
}
}
设置好模板后,保存一下。
接下来,在属性栏中,选择数据库对象(表格),点击"..."按钮,弹出窗口:
接着,改是添加CommonUtility.cs添加进来的时候了,它包括一些数据库类型转c#类型、首字母大写的方法:
using
System;
using
System.Text;
using
CodeSmith.Engine;
using
SchemaExplorer;
using
System.ComponentModel;
using
System.Data;
namespace
Common.Data
{
/**/
///
<summary>
///
TemplateRule
///
</summary>
public
class
CommonUtility
{
//
get Columns info by TableName
public
ColumnSchemaCollection GetColumnCollectionByTable(TableSchema table)
{
ColumnSchemaCollection columns
=
new
ColumnSchemaCollection(table.Columns);
return
columns;
}
//
Get camelcase name,such as Customer,
public
string
GetCamelCaseName(
string
str)
{
return
str.Substring(
0
,
1
).ToUpper()
+
str.Substring(
1
);
}
//
Get ,user,private const String USER_FIELD = "User"
public
string
GetMemberConstantDeclarationStatement(ColumnSchema column)
{
return
GetMemberConstantDeclarationStatement(
"
public const String
"
,column);
}
//
such as public const String USER_TABLE = "User"
public
string
GetTableConstantDeclarationStatement(TableSchema table)
{
return
GetMemberConstantDeclarationStatement(
"
public const String
"
,table);
}
//
suck as USER_TABLE
public
string
GetUpperStatement(TableSchema table)
{
return
table.Name.ToUpper()
+
"
_TABLE
"
;
}
//
suck as USER_FIELD
public
string
GetUpperStatement(ColumnSchema column)
{
return
column.Name.ToUpper()
+
"
_FIELD
"
;
}
//
such as USER_TABLE = "User"
public
string
GetMemberConstantDeclarationStatement(
string
protectionLevel,TableSchema table)
{
return
protectionLevel
+
GetUpperStatement(table)
+
"
= "
"
+
GetCamelCaseName(table.Name)
+
"
"
"
;
}
//
such as USERID_FIELD = "Userid"
public
string
GetMemberConstantDeclarationStatement(
string
protectionLevel,ColumnSchema column)
{
return
protectionLevel
+
GetUpperStatement(column)
+
"
= "
"
+
GetCamelCaseName(column.Name)
+
"
"
"
;
}
public
string
GetCSharpVariableType(ColumnSchema column)
{
switch
(column.DataType)
{
case
DbType.AnsiString:
return
"
string
"
;
case
DbType.AnsiStringFixedLength:
return
"
string
"
;
case
DbType.Binary:
return
"
byte[]
"
;
case
DbType.Boolean:
return
"
bool
"
;
case
DbType.Byte:
return
"
int
"
;
case
DbType.Currency:
return
"
decimal
"
;
case
DbType.Date:
return
"
DataTime
"
;
case
DbType.DateTime:
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
"
;
}
return
null
;
}
public
string
GetCSharpBaseType(ColumnSchema column)
{
switch
(column.DataType)
{
case
DbType.AnsiString:
return
"
System.String
"
;
case
DbType.AnsiStringFixedLength:
return
"
System.String
"
;
case
DbType.Binary:
return
"
System.Byte[]
"
;
case
DbType.Boolean:
return
"
System.Boolean
"
;
case
DbType.Byte:
return
"
System.Int32
"
;
case
DbType.Currency:
return
"
System.Decimal
"
;
case
DbType.Date:
return
"
System.DataTime
"
;
case
DbType.DateTime:
return
"
System.DataTime
"
;
case
DbType.Decimal:
return
"
System.Decimal
"
;
case
DbType.Double:
return
"
System.Double
"
;
case
DbType.Guid:
return
"
System.Guid
"
;
case
DbType.Int16:
return
"
System.Int16
"
;
case
DbType.Int32:
return
"
System.Int32
"
;
case
DbType.Int64:
return
"
System.Int64
"
;
case
DbType.Object:
return
"
System.Object
"
;
case
DbType.SByte:
return
"
System.SByte
"
;
case
DbType.Single:
return
"
System.Single
"
;
case
DbType.String:
return
"
System.String
"
;
case
DbType.StringFixedLength:
return
"
System.String
"
;
case
DbType.Time:
return
"
System.TimeSpan
"
;
case
DbType.UInt16:
return
"
System.UInt16
"
;
case
DbType.UInt32:
return
"
System.UInt32
"
;
case
DbType.UInt64:
return
"
System.UInt64
"
;
case
DbType.VarNumeric:
return
"
System.Decimal
"
;
}
return
null
;
}
}
}
现在,点生成,你就能看到你想要的Model了,可能你需要修改类名(因为它们跟表名一致,而我一般命名表明,通常是"工程名缩写 + _ + 表的意义"。或者,你在CommonUtility.cs里面添加改名的方法)。
补充,CodeSmith中文教程链接:http://download.csdn.net/source/347104