上回书所产生的实体类有啥问题?
第一:所产生的这个类,根本编译不过去。
第二:这个类的类名永远是Person,即使产生了这个类,还得修改。
第三:命名空间也要改。
第四:……
行了,我知道了,一口吃不成一个大胖子,一个一个问题的解决。
先看编译过不去的原因:已经定义了一个名字为title_id的字段了,错误提示在title_id这个属性那里。原来是字段名称和属性名称冲突了,正确的应该是字段名称使用骆驼命名法,而属性用Pascal命名法。这好办,只需要将字段的第一个字母改为小写,属性的第一个字母改为大写。能直接使用字符串的方法不?可以,但是不是太落伍了,可以考虑写一个公共函数,这样别的地方要用的话也可以嘛。
函数部分终于可以使用了。
//以骆驼命名法格式化字符串
public string ToCamel(string s)
{
}
//以Pascal命名法格式化字符串
public string ToPascal(string s)
{
}
更改输出的代码段:
//字段部分
private <%=column.SystemType%> <%=ToCamel(column.Name)%>;
//属性部分
public <%=column.SystemType%> <%=ToPascal(column.Name)%>
{
}
第一个问题完美解决。
第二个问题:想要让类名变化,最好让类名和表名有关系。啊哈,表名能不能来做类名呢?
可以,就是又产生一个小问题,因为表名通常为复数形式,能不能改成单数啊?
这个…,这个…,(变态…真变态,难道让我去处理不规则名词的复数到单数形式,碗大的汗珠…)行,只要去掉表名后的“s”嘛,小菜一碟(此处应表面不漏声色,把糊弄进行到底,当然我们处理绝大多数的问题,绝少数问题留给上帝解决。),不就是一个函数的问题吗。瞧好了。
public string GetClassName(TableSchema table)
{
}
将“Person”换了。
class <%=GetClassName(this.SourceTable)%>
第二个问题完美解决。
第三个问题:命名空间可和表名没啥关系,不过一般情况下,都将命名空间设置为Model或者Entity,可是到底选择哪一个什么?这还真是个问题,这么复杂的问题一般我们都不处理,留给用户处理,他想用哪个就是那个。在模板上加个参数,也就是加一个Property声明嘛,让他自己填,他爱填啥就是啥。
在声明部分添加:
<%@ Property Name=”NameSpace” Type=”System.String” Default=”Model” Optional=”False” Category=”” Description=”” Editor=”” EditorBase=”” Serializer=”” %>
为啥加个Default属性?
这是防万一的招,如果每个属性都让用户填写,难免没有信心继续使用,只让用户必须填写那些必须填写的内容,其他的辅助项目,给个默认值,让用户省心,也就是让我们省心,如此好事,为何不做?!
将namespace换了。
namespace <%=NameSpace%>
第三个问题完美解决。
还有第四个呢。
下回再说。
书接上回。
上回书中所产生的实体类,编译没有问题,使用也没有问题。那你还要咋么?
可是…可是…毕竟看起来不太舒服。
哪里不舒服?
虽然说“System.String”和“string”都是一回事,但是我们写的程序毕竟不是用MSIL语言写的啊,是用C#啊,最好别用CTS中的数据类型,大老,你说呢?
(能提出这个问题的,一律是好娃,可是好娃就是麻烦,净提一些精益求精的问题,搞死人了。)啊,这个问题啊,先说前提,CodeSmith不能把System.String直接转换为string,不过,常用的数据类型就不多的几种,可以考虑,采用分支结构,挨个转换嘛。这就是程序员伟大的地方,知其不可而为之,而且还为的挺好的。
解决的函数如下:
public string GetCSDataType(ColumnSchema column)
{
}
大老啊,你…你…你忽悠我,这里明明没有用到“System.String”和其他的CTS中的类型啊,忽悠人也不能这样啊。
小子无知,焉敢多舌。这事难道为师不知道?!为师是希望你能顿悟,没想到啊没想到,唉…………。
如果咱们用“System.String”和其他的CTS中数据类型的名字是不是可以做得到呢?当然是完全可以,可是在case的后面要自行填写字符串常量,case的结果处,是不是也要返回一个字符串常量,为师一贯以实践“懒人创造了世界,世界是为懒人创造的”的信条为己任,能少写就少写,能不写就不写,这样是不是太麻烦了嘛。
无论是从列结构上获取的SystemType还是DataType属性,都是用来表达这个列的数据类型的,尽管他们分别是CTS和SQL中的数据类型,从CTS转换和从SQL转换,有什么本质差别不?可是DataType是个枚举类型的属性,如果在VS.Net2005中,一旦switch一个枚举变量,可以自动生成这个枚举类型中所有的枚举值的case分支,这样,咱们只需要填写case的结构就可以了。
小子,悟了吗?要不要为师给你来个当头棒喝?
大老,明白了(敢不明白,不明白就拿大棒子敲,谁敢不明白)。
好的,那么将这个函数放在他应该在的地方,怎么样啊?
好。
经过上面几次的训练,生成实体类的模板应该可以做了。是不是只能做传统编程语言的源代码?
当然不是,如果将传统的编程语言的源代码看作普通的文本文件,那么我们前几次生成的源代码可以认为是后缀名为“.cs”的文本文件而已,既然能生成后缀为“.cs”的,那么其他的呢?
其实只要是源代码,一般都是文本文件格式的。
下面我们以一种非传统编程语言来演示CodeSmith生成内容的多样性。
一般情况下,我们是先有数据库文档,然后才有具体的数据库实现,可是现实中,并不总是这样的,很有可能我们是先设计的数据库,到了该提交工程的时候,才想起来,噢,麻烦了,数据库文档还没呢。
让程序员去写程序,问题不大,可是让他做这些重复的,机械性的劳动,不光是程序员回厌烦,其他人也是这样的,由于这个原因,人们才发明了各式各样的机器来减轻劳动强度。
可是,机器的产生光是减轻劳动强度吗?其实他还可以降低出错的概率,我常说,人有两个最大的优点:一是会犯错误,一是会遗忘。
大老,你就忽悠吧,犯错误是优点?遗忘是优点?
当然是优点了,人类社会的哪一次进步不是从错误中诞生的,没有遗忘,意味着你的脑子中充斥的是大量的无用的,过时的信息。
好了,言归正传,我们开始设计数据库文档。
按照以前的套路,先得知道生成的文档长的啥样。一般的数据库文档,无外乎表结构,视图,存储过程。
从简单开始吧,一般的表结构中包括以下几项内容:列名,数据类型,长度,精度,小数位数,是否为标识列,是否为主键,是否为外键,是否为空,有无默认值等。
一般将这些内容放入一张表格中来展示,目前展示表格的文件有很多,比如Excel、Word、Html、Xml等,但是,Excel、Word文件内容一般为二进制格式,不是纯粹的文本文件,因而可以选择的文件格式为Html和Xml,相对来说Html对格式的要求不严格,因而我们准备将我们生成数据库文档设置为Html格式。
在Html中也有表格,不过是以标记的方式展示的。样子应该象下图:
列名 | 类型 | 长度 | 是否为空 | 主键 | 外键 | 是否标识列 |
---|---|---|---|---|---|---|
au_id | char | 11 | | Y | | |
au_lname | varchar | 40 | | | | |
au_fname | varchar | 20 | | | | |
phone | char | 12 | | | | |
address | varchar | 40 | Y | | | |
city | varchar | 20 | Y | | | |
state | char | 2 | Y | | | |
zip | char | 5 | Y | | | |
contract | bit | 1 | | | | |
在这个需求中,我们要使用DatabaseSchema,TableSchema,ColumnSchema,在数据库结构中有表结构的集合,在表结构中有列结构的集合,这样,我们可以用两个循环嵌套的方式,生成所有的表的文档。
<%@ CodeTemplate Language=”C#” TargetLanguage=”Html” Src=”” Inherits=”” Debug=”False” Description=”Template description here.”
<%@ Property Name=”Developer” Type=”String” Default=”” Optional=”False” Category=”Context” Description=”作者” OnChanged=”” Editor=”” EditorBase=”” Serializer=”” %>
<%@ Property Name=”SourceDB” Type=”SchemaExplorer.DatabaseSchema” Default=”” Optional=”False” Category=”Context” Description=”数据库名称” OnChanged=”” Editor=”” EditorBase=”” Serializer=”” %>
<%@ Assembly Name=”SchemaExplorer” %>
<%@ Assembly Name=”System.Data” %>
<%@ Import Namespace=”System.Data” %>
<%@
<%– 类生成内容在此–%>
<html>
<head><title><%=this.SourceDB.Name%></title></head>
<style>
</style>
<body>
<%foreach(TableSchema table in SourceDB.Tables){%>
<%}%>
</body>
</html>
<script runat=”template”>
public string IsID(ColumnSchema column)
{
}
public string IsNull(ColumnSchema column)
{
}
public string IsPK(ColumnSchema column)
{
}
public string IsFK(ColumnSchema column)
{
}
public string GetTableName(TableSchema table)
{
}
public string GetColumnName(ColumnSchema column)
{
}
public bool HasLength(ColumnSchema column)
{
}
</script>
转自 http://blog.sina.com.cn/s/articlelist_1229294631_0_1.html