前言
其实本文所说的思路产生以很久以前,本人也曾将用于多个小型项目开发之中,用下来的整体说还是比较满意。按理说,自己既然用了那么多次也应写些心得或是总结出来吧,无奈一是自己太懒二是文字功底有限,只好罢了!拖到了现在,方提指敲写,也不知成文怎样,由大家评说吧。
本文作为开发笔记以流水的方式敲写,其中不讨论开发模式之间的优劣;如大家有好的建议也希望直面地提出来,我呢,以求进步!
文中所举的例子:ASP.NET (Net1.1)+ Access 基础上所搭建。
CodeSmith概述
CodeSmith中文我不知叫什么,不太好解释,必竟这是“工业化”的东西,有点抽象,顾名思义(Code Smith 代码工匠),就是生成代码的东西;CodeSmith作用在于生成代码模板,减少手工书写代码的工作,提高生产效率,增加剥夺收入。习惯上,我们项目组里在应用CodeSmith有这着这样的感受:C#的语法,ASP的写法。不过话也得说回来,在ASP时代,我们没有这样的“艳遇”,那时代码的生成,只能在自己编写ASP Generator里生成,并且编写过程中也没有这么好的IDE支持。
或许有人会这样认为,既然有了CodeSmith,那么好多逻辑不是一下子就可以生成了吗?干嘛要用什么ECC,烦!事实上,这话有部分多,也有大部分不对!是的,CodeSmith能快速地根据模板生成大量的代码,但不有能生成所有的代码,因为在一个逻辑必须根据具体的应用环境情况下随时变动逻辑的代码,其没有任何的意义可言。平时在开发过程中,我们也对没有接触过的CodeSmith的伙伴这样说:Code Smith 主要的是生成DAO(特别是与数据库的表中粒度一一对应的书写中)与相对稳定的应用对象逻辑代码,其不是万能的!生成的代码必须是软件开发过程中所已经协商好的开发模式的反映,而不是什么都要CodeSmith生成,否则生成的代码,谁也看不懂,更不用说维护了或是项目组内成员的学习了。
下面我就简单提一下CodeSmith初学者经常提到了几个问题,至于CodeSmith具体是怎样应用的,我们可以查看其自带的学习例子或是在网上搜索,教程一大把。如下:
1.CodeSmith怎样与数据库结合
CodeTemplate里本身已经提供了访问了数据库的属性:
///////////////////////////////////////////////////////////////////////
数据库的连接
<%@ Property Name="SourceTable" Type="SchemaExplorer.TableSchema" Category="1. Context"
Description="Table that the stored procedures should be based on." %>
在DataSource里Provider type t选择ADOXschemaProvider,输入类似的ConnectionString:Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:/开发项目/基于ACCESS的小型系统.NET/BreakerSimply/DataBase/BreakerSimply.mdb
//////////////////////////////////////////////////////////////////////////////////////
表的访问
//writeable columns Data
#region IsWritableColumns
public string IsWritableColumns()
{
//把ID 排除
string sTemp ="";
foreach(ColumnSchema column in SourceTable.Columns)
{
if (column.Name.ToLower()=="id")
{
}
else
{
sTemp +=this.GetPropertyName(column)+",";
}
}
return sTemp;
}
#endregion
public string GetNativeTypeString(ColumnSchema column)
{
string sColumnType = "";
string sTemp = column.NativeType.ToString();
//Debug.Print(sTemp);
//Response.WriteLine("{0}={1}", column.Name, sTemp);
//Debugger.Break();
sTemp = sTemp.ToLower();
switch(sTemp)
{
case "advarwchar":
sColumnType = "OleDbType.VarWChar";
break;
case "adinteger":
sColumnType = "OleDbType.Integer";
break;
case "addate":
sColumnType = "OleDbType.Date";
break;
case "adlongvarwchar":
sColumnType = "OleDbType.VarWChar";
break;
case "adboolean":
sColumnType = "OleDbType.Boolean";
break;
case "adcurrency":
sColumnType = "OleDbType.Currency";
break;
case "float":
sColumnType = "OleDbType.Float";
break;
case "image":
sColumnType = "OleDbType.Image";
break;
case "int":
sColumnType = "OleDbType.Int";
break;
case "money":
sColumnType = "OleDbType.Money";
break;
case "nchar":
sColumnType = "OleDbType.NChar";
break;
case "ntext":
sColumnType = "OleDbType.NText";
break;
case "nvarchar":
sColumnType = "OleDbType.NVarChar";
break;
case "real":
sColumnType = "OleDbType.Real";
break;
case "smalldatetime":
sColumnType = "OleDbType.SmallDateTime";
break;
case "smallint":
sColumnType = "OleDbType.SmallInt";
break;
case "smallmoney":
sColumnType = "OleDbType.SmallMoney";
break;
case "text":
sColumnType = "OleDbType.Text";
break;
case "timestamp":
sColumnType = "OleDbType.Timestamp";
break;
case "tinyint":
sColumnType = "OleDbType.TinyInt";
break;
case "uniqueidentifier":
sColumnType = "OleDbType.UniqueIdentifier";
break;
case "varbinary":
sColumnType = "OleDbType.VarBinary";
break;
case "varchar":
sColumnType = "OleDbType.VarChar";
break;
case "variantariant":
sColumnType = "OleDbType.Variantariant";
break;
default:
sColumnType = "";
break;
}
return sColumnType;
}
2.CodeSmith生成后的代码存放。
如下
<script runat="template">
#region Template Property Script
private string _outputDirectory = String.Empty;
[Editor(typeof(System.Windows.Forms.Design.FolderNameEditor), typeof(System.Drawing.Design.UITypeEditor))]
public string OutputFolder
{
get
{
if (_outputDirectory.Length == 0)
{
string sOutputFolder = this.CodeTemplateInfo.DirectoryName;
if(!sOutputFolder.EndsWith("//"))
sOutputFolder += "//";
sOutputFolder += "Tempout//Model";
if(!System.IO.Directory.Exists(sOutputFolder))
{
System.IO.Directory.CreateDirectory(sOutputFolder);
}
return sOutputFolder;
}
return _outputDirectory;
}
set
{
if (value.EndsWith("//")) value = value.Substring(0, value.Length - 1);
_outputDirectory = value;
}
}
#endregion
</script>
CodeSmith软件自带了很多很好的例子,我也是从上面学的~~。
什么ECC
ECC由Engine、Class、Collection三部分构成,Engine实际上是个控制器,负责怎样创建返回Class,Class表示现实世界的实体,具备详细的属性,Collection就是装载Class的集合容器了; ECC 有人称之为“与实现无关无关的应用框架”,或许这有点夸大之嫌,什么叫做“与实现无关”,晕死。ECC确实提供了松散耦合的体系结构,它的出现使被操作的对像之间更显得独立,更为清晰,并且在很大程度上也降低了业务与具体逻辑的耦合
在ASP.NET中,我们还得考虑这么个问题,数据控件的数据绑定问题:控件支持CollectionBase的绑定,支持自定义行为(特别跨对像之间的数据操作);这些都能在ECC的模式里得到良好的解决。
实例中的ECC架构
本文将以一个具体的例子进行说明:(本想贴些图,但发现贴了好几次都不成功,只好罢了)
这个例子主要是实现文章的管理,如分类与相关CRUD,也就是平时所说的做了个小小的新闻发布系统:栏目表(ArticleColumn) 与 Article表,两者是一对多的关系
ArticleColumn表结构
ID 自动编号
UUID UUID
Name 栏目名
Class 级数
Order 排序
CreatedTime 创建时间
IsActive 是否启用
Article表结构
ID 自动编号
UUID UUID
ColumnID 栏目ID
Title 标题
Content 内容
Author 作者
CreatedTime 创建时间
IsActive 是否启用
一般情况下,我是按这样的工作流程:
1. 分析所要设计的系统有几个可以称为“对像”的元素;
2. 接着,用toghter画一下设计下逻辑图,生成初步的“原始代码”;
3. 在“原始代码”,添血加肉,完成初步的逻辑;
4. 以上面的代码为骨架,在CodeSmith编写相应的代码。
以纯粹文章功能模块为例:
ArticleMD (与数据库的ARTICLE表建立一一的映射,将reader读出数据装载入Article)Article (继承MD,处理关联的对像数据,如在这里根据文章的ID获取该文章的栏目)ArticleDAO (数据库访问逻辑,原始的CRUD操作逻辑)ArticleBL (继承DAO,根据业务需要,对CRUD的操作进行进一步的封装)ArticleCollection 基于CollectionBase,创建Aritlce集合;这个类可以从MSDN的例子获得。具体的码如下:
先做饭~,明天再写