code smith 使用介绍
利用CodeSmith为SQL Server CE生成项目代码
摘要:CodeSmith是很多.NET开发人员至爱的开发辅助工具,它能够使开发人员从大量枯燥无味的重复编码中解脱,集中精力解决实际业务问题和技术问题。本文将介绍如何将CodeSmith用于Windows Mobile项目,以SQL Server Compact Edition数据库作为代码生成的依据生成项目代码。
什么是代码生成器?
代码产生器是产生式编程(Generative Programming)在实际应用中的一种产物。它以系统建模为基础,通过抽象各种系统间的共性与特性,利用代码模板和组件重用技术,自动产生满足客户需求的软件产品。从而降低成本,减少软件推向市场的时间,并且保证更好的产品质量。最终取得规模经济和范围经济的优点。2004年我还在大学读书的时候曾开发过一个基于模板引擎的代码生成器——RapidTier,当时这个作品还获得了广东省高校杯软件设计大赛的二等奖。在.NET的世界里,目前最有名的代码生成器当属CodeSmith和MyGeneration。这两款代码生成器都是基于模板引擎的,使用起来方便灵活,而且模板资源非常丰富。
CodeSmith 简介
CodeSmith 是一个基于模板的代码生成器,你可以利用它来生成任何文本语言的代码。CodeSmith 生成的代码可以通过模板的属性来定制。CodeSmith 模板的语法跟 ASP.NET 非常相似,你可以在模板中使用 C# 或 VB.NET 控制代码的生成。通常,开发人员利用CodeSmith根据SQL Server或Oracle等大型数据库生成各种项目代码(如:存储过程、数据访问层、业务逻辑层、表现层等)。今天将向各位介绍如何利用 CodeSmith为移动数据库SQL Server Compact Edition生成Windows Mobile项目的代码。
配置SchemaProvider
CodeSmith通过SchemaProvider来支持各种数据库。在CodeSmith Professional 4.1.2安装后,默认只支持SQL Server、Oracle、Access、MySQL等数据库类型。如果需要支持其他类型的数据库,可以到网上搜索相关数据库的 SchemaProvider实现,或者自己手动编写代码实现ISchemaProvider接口。
最近,我从网上找到了SQL Server Compact Edition(3.1)的SchemaProvider实现,经过代码调整和调试,现在跟大家分享一下。可以从这里下载到这个SchemaProvider相关的DLL,下载后将其解压,并将 SchemaExplorer.SqlCeSchemaProvider.dll和System.Data.SqlServerCe.dll文件复制到 CodeSmith的SchemaProvider目录下(C:/Program Files/CodeSmith/v4.1/SchemaProviders)。
配置数据源
启动CodeSmith,点击左边停靠的Schema Explorer窗口上方点击“Manage Data Sources”工具栏按钮,打开Data Source Manager窗口。
Data Source Manager窗口打开后,点击Add按钮添加新的数据源。在Data Source窗口中,数据源名称(Name)输入“Northwind sqlce”,提供程序类型(Provider Type)选择SqlCeSchemaProvider,连接语句输入“data source=c:/Northwind.sdf”,假设你已经将SQL Server Compact Edition自带的Northwind.sdf数据库复制到C盘根目录了。
你可以通过点击Test按钮测试一下是否正常连接,然后点击OK保存数据源,回到Data Source Manager窗口,现在看到多了一个叫“Northwind sqlce”的数据源了。
“Northwind sqlce”数据源已经添加成功,点击Close按钮关闭Data Source Manager窗口。回到Schema Explorer窗口,展开“Northwind sqlce”数据源,浏览各个表的字段和属性。
生成代码
在CodeSmith右边停靠的Template Explorer窗口打开自带的模板“CodeSmith 4.1 Samples/ActiveSnippets/CSharp/TableProperties.cst”。这个模板可以从一个数据库的表的所有字段生成对应的实体类的所有属性(Property)定义代码。
模板被打开后,在CodeSmith右边停靠的Properties窗口选择SourceTable属性,点击旁边的“...”按钮浏览并选择一个Northwind.sdf数据库的表。这里我们选择Categories表,并点击Select按钮确定。
现在可以按F5生成代码了,生成的结果如下所示:
private int _categoryID;
public int CategoryID
{
get { return _categoryID; }
set { _categoryID = value; }
}
private string _categoryName;
public string CategoryName
{
get { return _categoryName; }
set { _categoryName = value; }
}
private string _description;
public string Description
{
get { return _description; }
set { _description = value; }
}
private System.Byte[] _picture;
public System.Byte[] Picture
{
get { return _picture; }
set { _picture = value; }
}
你还可以选择其他的表或其他模板生成代码试一试,体验一下CodeSmith的强大之处。
总结
通过上面的介绍和示例演示,相信大家都认同CodeSmith确实很好很强大。当然,这里只是演示了一个很简单的例子,你可以根据项目的实际需要自己编写模板,按自己的方式去生成项目代码。编写模板最快捷的方法就是基于现有比较类似的模板进行修改。CodeSmith之所以能够用于SQL Server Compact Edition数据库的代码生成,除了前面提到的它通过SchemaProvider支持各种类型的数据库,还有一点很重要的就是SQL Server Compact Edition支持桌面平台,如果是SQL Server Mobile就没有办法做到这一点了。
相关下载:SqlCeSchemaProvider.rar
http://upto.cnblogs.com/
========
code Smith 使用学习
CodeSmith在执行模版时通过调用一些API来完成的,主要经过了以下这几步的操作:
编译一个模版
显示编译错误信息
创建一个新的模版实例
用元数据填充模版
输出结果
下面这段代码显示了这些操作:
CodeTemplateCompiler compiler = new CodeTemplateCompiler("..//..//StoredProcedures.cst");
compiler.Compile();
if (compiler.Errors.Count == 0)
{
CodeTemplate template = compiler.CreateInstance();
DatabaseSchema database = new DatabaseSchema(new SqlSchemaProvider(), @"Server=(local)/NetSDK;Database=Northwind;Integrated Security=true;");
TableSchema table = database.Tables["Customers"];
template.SetProperty("SourceTable", table);
template.SetProperty("IncludeDrop", false);
template.SetProperty("InsertPrefix", "Insert");
template.Render(Console.Out);
}
else
{
for (int i = 0; i < compiler.Errors.Count; i++)
{
Console.Error.WriteLine(compiler.Errors[i].ToString());
}
}
如果你需要提供一个复杂的组合用户界面来输入元数据,这时就要添加设计器的支持。换句话说,除此之外没有别的办法来输入你自定义的元数据类型。添加设计器的支持,首先你要创建一个Editor作为自定义的类型,一个Editor其实就一个继承于.NET 中的System.Drawing.Design.UITypeEditor类的子类。
安装CodeSmith后在,在C:/Program File/CodeSmith/ SampleProjects 文件夹下有很多SampleCustomProperties的工程。例如:DropDownEditorProperty是一个把字符串和布尔类型的值结合在一起的元数据,它提供了一个类DropDownEditorPropertyEditor继承于System.Drawing.Design.UITypeEditor。
[Editor(typeof(CodeSmith.Samples.DropDownEditorPropertyEditor), typeof(System.Drawing.Design.UITypeEditor))]
public class DropDownEditorProperty
在使用的时候跟其它的元数据类型是一样,不过别忘记添加对程序集的引用,引用CodeSmith默认的是不认识该类型的。
<%@ Property Name="DropDownEditorProperty" Type="CodeSmith.Samples.DropDownEditorProperty" Category="Options" Description="This property uses a custom dropdown editor." %>
<%@ Assembly Name="SampleCustomProperties" %>
当用户想要编辑DropDownEditProperty时,单击CodeSmith属性面板将会显示如下的自定义对话框:
在CodeSmith中,如果生成的代码是SQL脚本,则可以在生成代码完成时自动执行生成的代码,也就是在生成的SQL脚本的同时在数据库中创建新的对象。
用BaseTemplates.ScriptUtility对象提供ExecuteScript方法可以实现,如果想在生成代码完成后立即执行生成的脚本,可以很方便的通过重载OnPostRender来实现。
在使用之前,先添加对下列程序集的引用:
<%@ Assembly Name="CodeSmith.BaseTemplates" %>
<%@ Import Namespace="CodeSmith.BaseTemplates" %>
看下面的这个例子:
protected override void OnPostRender(string result)
{
// execute the output on the same database as the source table.
CodeSmith.BaseTemplates.ScriptResult scriptResult =
CodeSmith.BaseTemplates.ScriptUtility.ExecuteScript(this.SourceTable.Database.ConnectionString,
result, new System.Data.SqlClient.SqlInfoMessageEventHandler(cn_InfoMessage));
Trace.Write(scriptResult.ToString());
base.OnPostRender(result);
}
在这个例子中SourceTable是一个类型为SchemaExplorer.TableSchema.的属性,使用的时候需要调整部分代码来获取数据库的连接以便在生成代码完成后执行脚本。
在CodeSmith中使用CodeTemplateInfo可以获取当前模版的一些信息:
属性
返回值
CodeBehind
Gets the full path to the code-behind file for the template (or an empty string if there is no code-behind file).
ContentHashCode
Gets the hash code based on the template content and all template dependencies.
DateCreated
Gets the date the template was created.
DateModified
Gets the date the template was modified.
Description
Gets the description.
DirectoryName
Gets the name of the directory the template is located in.
FileName
Gets the name of the template file.
FullPath
Gets the full path to the template.
Language
Gets the template language.
TargetLanguage
Gets the target language.
看一下一个具体的使用例子:
<%@ CodeTemplate Language="VB" TargetLanguage="Text" Description="Demonstrates CodeTemplateInfo." %>
<% DumpInfo() %>
执行该模版输出如下(环境不同,输出也不同):
Template: CodeTemplateInfo.cst
Created: 6/29/2005 8:54:19 PM
Description: Demonstrates CodeTemplateInfo.
Location: C:/Program Files/CodeSmith/v3.0/SampleTemplates/Test/CodeTemplateInfo.cst
Language: VB
Target Language: Text
Progress对象可以在CodeSmith生成代码时给用户显示一个进度条,当生成代码的时间很长时非常有用。如果你使用的是CodeSmith Explorer,进度条将显示在Generate按钮的左边:
如果使用的是CodeSmith Studio,进度条将显示在状态栏上:
使用Progress和在WinForm中使用进度条差不多,需要设置它的最大值和步长:
this.Progress.MaximumValue = 25;
this.Progress.Step = 1;
如果想显示出进度,需要调用PerformStep方法:
this.Progress.PerformStep();
在CodeSmith中,以下几个快捷键有助于我们快速输入。
1.Ctrl + Shift + C
在空行上,按下Ctrl + Shift + C后将会录入一个代码块。
<% %>
2.Ctrl + Shift + Q
按下Ctrl + Shift + Q后录入一个脚本块。
3.Ctrl + Shift + V
对代码块反转,如有下面这样一行代码:
<% for(int i=0;i<10;i++){}%>
在两个大括号之间按下Ctrl + Shift + V后,将变成如下代码:
<% for(int i=0;i<10;i++){%> <%}%>
4.Ctrl + Shift + W
按下Ctrl + Shift + W后会录入一个输出的代码块:
<%= %>
注意:在使用快捷键的时候,如果想要把一段代码之间放在录入的标记中间,首先选中这些代码,再按下快捷键组合。比如我们有一段这样的代码,想把它放在
========
CodeSmith的基础模版类
基础模版类
类型描述:
Batch
OutputFileCodeTemplate 模版通过继承此类能够在生成过程中把他们的输出保存到文件中
ScriptError 在脚本执行中出现一个错误
ScriptErrorCollection
ScriptResult 一个脚本的运行结果包含一些已经发生的错误
ScriptUtility 这个类能用来在数据库上执行Sql脚本。
SqlCodeTemplate 继承此类的模版当从一个Sql数据源生成代码时能够获得很多有用的帮助方法
StringUtility 多种处理string型的方法
各类型下的成员属性及方法
Batch Class
属性
Content
LineCount
StartLineNumber
方法
Finalize 在一个对象再次创建之前获得空闲资源并且执行其他的清空操作
MemberwiseClone 建立现有对象的副本
OutputFileCodeTemplate Class
属性
CodeTemplateInfo 得到当前模版的信息
OutputFile 此属性用来指定一个保存模版输出的输出文件名
Progress 提供一种方式汇报模版的执行进程
Response 模版输出返回流。此属性可以在程序中写出流
State 模版实例的状态
ValidationErrors 得到模版的错误
方法
CopyPropertiesTo 把匹配的属性拷贝到另一个代码模版实例中
GetCodeTemplateInstance 重载,得到指定模版的实例
GetFileName 为模版的输出得到一个默认的名字
GetProperties 得到模版的所有属性
GetProperty 得到模版的指定属性
GetRequiredProperties 得到模版上所有必要的属性
GetType 得到当前实例类型
ParseDefaultValue 解析属性的默认值
SavePropertiesToXml 以XML保存属性
SavePropertiesToXmlFile 保存属性到一个XML文档
SetProperty 重载,保存指定的属性值
ToString
ScriptError Class
属性
方法
Finalize 在一个对象再次创建之前获得空闲资源并且执行其他的清空操作
MemberwiseClone 建立现有对象的副本
ScriptUtility Class
属性
ConnectionString 执行脚本时使用此连接字符串
Script 执行的脚本
方法
ExecuteScript 重载,执行脚本
SqlCodeTemplate Class
属性
CodeTemplateInfo 得到当前模版的信息
OutputFile 此属性用来指定一个保存模版输出的输出文件名
Progress 提供一种方式汇报模版的执行进程
Response 模版输出返回流。此属性可以在程序中写出流
State 模版实例的状态
ValidationErrors 得到模版的错误
方法
CopyPropertiesTo 把匹配的属性拷贝到另一个代码模版实例中
GetCamelCaseName Returns a camel cased name from the given identifier.
GetCodeTemplateInstance 重载,得到指定模版的实例
GetCSharpVariableType 基于给定列返回C#的变量类型
GetFileName 为模版的输出得到一个默认的名字
GetMemberVariableDeclarationStatement
重载,返回C#成员变量声明语句
GetMemberVariableDefaultValue
基于一个列的数据类型返回一个默认值
GetMemberVariableName 为一个给定标示返回一个C#成员变量名
GetProperties 得到模版的所有属性
GetProperty 得到模版的指定属性
GetPropertyName 返回指定列的公有属性的名字
GetReaderMethod Returns the name of the typed reader method for a given column.
GetRequiredProperties 得到模版上所有必要的属性
GetSpacedName Returns a spaced out version of the identifier.
GetSqlDbType 返回一个给定列的SqlDbType
GetSqlParameterExtraParams
为ADO的参数声明生成额外的参数
GetSqlParameterStatement
重载,返回给定列的T-Sql的参数声明
GetSqlParameterStatements
重载,给指定列加一个参数到ADO对象生成一个指定声明(Generates an assignment statement that adds a parameter to a ADO object for the given column. )
GetValidateStatements 基于某列生成一组确认声明
IncludeEmptyCheck 确定一个给定列是否可以为空
IncludeMaxLengthCheck 确定一个给定列的类型是否需要最大长度的定义
IsUserDefinedType 确定是否一个给定列用了一个UDT(用户定义类型)
ParseDefaultValue 解析属性的默认值
SavePropertiesToXml 以XML保存属性
SavePropertiesToXmlFile 保存属性到一个XML文档
SetProperty 重载,保存指定的属性值
========
CodeSmith 使用实例
StringCollection提供了一种集合的输入方式,在代码中,可以用Array的方式来引用。在使用这个类之前,在模版中我们必须添加对CodeSmith.CustomProperties程序集的引用:
<%@ Assembly Name="CodeSmith.CustomProperties" %>
添加完程序集之后,我们就可以使用StringCollection在脚本块中定义一个属性:
<%@ Property Name="List" Type="CodeSmith.CustomProperties.StringCollection" Category="Custom" Description="This is a sample StringCollection" %>
执行该模版时,这个属性将在属性窗体中显示为一个按钮:
单击按钮,将会弹出一个String Collection Editor对话框:
当然也可以直接在属性窗口中编辑StringCollection。
模版代码如下:
<%@ CodeTemplate Language="C#" TargetLanguage="C#" %>
<%@ Assembly Name="CodeSmith.CustomProperties" %>
<%@ Property Name="List" Type="CodeSmith.CustomProperties.StringCollection" Category="Custom" Description="This is a sample StringCollection" %>
using System;
namespace Test
{
/**////
/// 测试StringCollection
///
public class Test
{
public static void Main(string[] args)
{
<%for(int i = 0;i
Console.WriteLine(<%=List[i]%>);
<%}%>
}
}
}
成后的代码:
using System;
namespace Test
{
/**////
/// 测试StringCollection
///
public class Test
{
public static void Main(string[] args)
{
Console.WriteLine(Apples);
Console.WriteLine(Fish);
}
}
}
StringCollection的重要属性和方法:
公共属性
名称
描述
Count
获取StringCollection中包含的字符串的数目
IsReadOnly
获取用于指示StringCollection是否为只读的值
IsSynchronized
获取一个值,该值指示对StringCollection 的访问是否为同步的(线程安全的)
Item
获取或设置指定索引处的元素。在C# 中,该属性为 StringCollection 类的索引器
SyncRoot
获取可用于同步对StringCollection 的访问的对象
公共方法
名称
描述
Add
将字符串添加到 StringCollection 的末尾
AddRange
将字符串数组的元素复制到 StringCollection 的末尾
Clear
移除 StringCollection 中的所有字符串
Contains
确定指定的字符串是否在 StringCollection 中
CopyTo
从目标数组的指定索引处开始,将全部 StringCollection 值复制到一维字符串数组中
IndexOf
搜索指定的字符串并返回 StringCollection 内的第一个匹配项的从零开始的索引
Insert
将字符串插入 StringCollection 中的指定索引处
Remove
从 StringCollection 中移除特定字符串的第一个匹配项
RemoveAt
移除 StringCollection 的指定索引处的字符串
========
CodeSmith 实例2
FileNameEditor类给我们提供了在CodeSmith属性面板中弹出打开或保存文件对话框的方式,在使用时,首先在模版中得添加对程序集CodeSmith.CustomProperties的引用。然后就可以在模版中定义一个属性来使用FileNameEditor:
1
24
25
当我们执行该模版时,在属性面板中同样显示为一个按钮:
单击该按钮,弹出一个保存文件的对话框:
我们也可以通过FileDialogAttribute来自定义弹出的对话框,修改模版为:
1private string _openFileName = @"c:/temp/test.txt";
2
3
4[Editor(typeof(FileNameEditor), typeof(System.Drawing.Design.UITypeEditor)),
5
6FileDialogAttribute(FileDialogType.Open, Title="Select Input File"),
7
8Category("Custom"), Description("User selected file.")]
9
10
11
12public string OpenFileName
13
14{
15
16 get {return _openFileName;}
17
18 set {_openFileName= value;}
19
20}
21
22
弹出的对话框如下所示:
当我们想用一个文件夹的名称来代替文件时,可以使用FolderNameEditor类。
1<%@ Assembly Name="System.Design" %>
2
12
13
FileNameEditor重要方法和属性介绍:
公共方法:
名称
描述
EditValue
使用由 GetEditStyle 方法提供的编辑器样式编辑指定的对象
GetEditStyle
获取 EditValue 方法所使用的编辑样式
========
CodeSmith应用实例(一)
版权声明:本文为博主原创文章,未经博主允许不得转载。
一、一个简单的例子
这个例子仅是一个简单的应用,在我翻译并学习完CodeSmith的英文帮助文档后,对CodeSmith有了一定的了解,开始着手编写一些CodeSmith应用模板,今天按照最早提到的例子自行编写了一个基于表的添加存储过程的生成模板。具体语法前面基础中已做过详细解释这里仅是一个小综合应用的例子,望对大家学习CodeSmith有很好的帮助。我的同事也写了几个CodeSmith的技巧的文章http://terrylee.cnblogs.com/大家有空去看看,写的很不错哦,都是针对于CodeSmith自定义属性编写的东东:)
1<%@ CodeTemplate Language="C#" TargetLanguage="T-SQL" Description="Create a procedure which have insert function base on a table." %>
2<%@ Assembly Name="SchemaExplorer" %>
3<%@ Import Namespace="SchemaExplorer" %>
4<%@ Property Name="SourceTable" Type="SchemaExplorer.TableSchema" Category="DataTable" Description="Table that the stored procedures should be based on." %>
5<%@ Property Name="Author" Type="String" Category="Context" Description="The author for this procedure."%>
6<%@ Property Name="Description" Type="String" Category="Context" Description="The description for this procedure."%>
7
30CREATE PROCEDURE dbo.<%=SourceTable.Name %>Insert
31/*
32==================================================
33Author:<%= Author %>
34CreatedTime:<%= System.DateTime.Now.ToShortDateString() %>
35Description:<%= Description %>
36==================================================
37*/
38<% for (int i = 0; i < SourceTable.Columns.Count; i++) { %>
39<%= GetSqlParameterStatement(SourceTable.Columns[i]) %><% if (i < SourceTable.Columns.Count - 1) { %>,<% } %> <% if (SourceTable.Columns[i].Description != "") { %>--<%= SourceTable.Columns[i].Description %><% } %>
40<% } %>
41AS
42Insert Into [<%= SourceTable.Name %>]
43(
44<% for (int i = 0; i < SourceTable.Columns.Count; i++) { %>
45[<%= SourceTable.Columns[i].Name %>]<% if (i < SourceTable.Columns.Count - 1) { %>,<% } %> <% if (SourceTable.Columns[i].Description != "") { %>--<%= SourceTable.Columns[i].Description %><% } %>
46<% } %>
47)
48Values
49(
50<% for (int i = 0; i < SourceTable.Columns.Count; i++) { %>
51@<%= SourceTable.Columns[i].Name %><% if (i < SourceTable.Columns.Count - 1) { %>,<% } %>
52<% } %>
53)
二、具有删除功能的模板
今天又根据CodeSmith的几个基本组件写出了基于表生成删除功能的存储过程代码生成模板。
昨天觉得添加的存储过程模板写的比较简单,今天准备详细介绍一下这个删除的模板。
首先介绍我们使用到的一个教本函数GetSqlParameterStatement(ColumnSchema column),其函数代码如下:
1public string GetSqlParameterStatement(ColumnSchema column)
2{
3 string param = "@" + column.Name + " " + column.NativeType;
4 switch (column.DataType)
5 {
6 case DbType.Decimal:
7 {
8 param += "(" + column.Precision + ", " + column.Scale + ")";
9 break;
10 }
11 default:
12 {
13 if (column.Size > 0)
14 {
15 param += "(" + column.Size + ")";
16 }
17 break;
18 }
19 }
20 return param;
21}
大家可以看到,这个函数需要传入一个ColumnSchema类型的参数,它代表一个数据表中的列,并且是一个列,然后根据ColumnSchema这个类具有的属性,对传入的列进行一些操作然后返回我们生成存储过程时需要的代码。
首先介绍一下ColumnSchema的一些常用属性,如下表:
属性Property
描述Description
AllowDBNull
是否允许空值NULL
Database
通过DatabaseSchema对象得到当前列所属的数据库
DataType
此数据对象的数据类型
Description
当前对象的描述
ExtendedProperties
用来存储SchemaObject的其他附加信息
IsForeignKeyMember
当前列是否为外键
IsPrimaryKeyMember
当前列是否为主键
IsUnique
当前列是否唯一
Name
列的名称
NativeType
列定义的数据类型
Precision
数据对象的精度
Scale
数据对象的范围(个人理解为需要保留小数的范围)
Size
数据对象的大小(例如:字符串长度为10)
SystemType
数据对象的系统类型
Table
当前列所属的数据表
下面为我们首先要生成存储过程,要自动生成的代码分成了红、绿、蓝三部分。
CREATE PROCEDURE dbo.CustomersDelete
/*
==================================================
Author:Bear-Study-Hard
CreatedTime:2005-12-28
Description:Delete a record from table Customers
==================================================
*/
@CustomerID nchar(5) --客户ID
AS
Delete From [Customers]
Where
[CustomerID] = @CustomerID
我们的这个脚本函数就是要实现拼出红色的部分,GetSqlParameterStatement函数接收到ColumnSchema类型的参数后,从其Name属性和NativeType属性拼出@CustomerID nchar部分,然后由于不同的数据类型尤其是数值类型和字符串类型的区别,会导致数据类型的大小会有所不同,这里仅对Decimal的数据类型进行了判断(Numeric和float等均需要这种处理),然后根据Precision属性得到精度并通过Scale属性得到了需要保留小数的范围。如果传出的为非Decimal类型字段则直接通过Size属性取出其大小即可。得到了(5)部分。最后的注释是为了生成的存储过程解读性好加上的,使用的是Description属性。
剩下的绿色部分和蓝色部分生成时比较简单,请各位自行学习。模板代码为:
1<%@ CodeTemplate Language="C#" TargetLanguage="T-SQL" Description="Create a procedure which have delete function base on a table.Must use PrimaryKey to delete a record." %>
2<%@ Assembly Name="SchemaExplorer" %>
3<%@ Import Namespace="SchemaExplorer" %>
4<%@ Property Name="SourceTable" Type="SchemaExplorer.TableSchema" Category="DataTable" Description="Table that the stored procedures should be based on." %>
5<%@ Property Name="Author" Type="String" Category="Context" Description="The author for this procedure." Optional="true"%>
6<%@ Property Name="Description" Type="String" Category="Context" Description="The description for this procedure." Optional="true"%>
7
30CREATE PROCEDURE dbo.<%=SourceTable.Name %>Delete
31/*
32==================================================
33Author:<%= Author %>
34CreatedTime:<%= System.DateTime.Now.ToShortDateString() %>
35Description:<%= Description %>
36==================================================
37*/
38<% for (int i = 0; i < SourceTable.PrimaryKey.MemberColumns.Count; i++) { %>
39<%= GetSqlParameterStatement(SourceTable.PrimaryKey.MemberColumns[i]) %><% if (i < SourceTable.PrimaryKey.MemberColumns.Count - 1) { %>,<% } %> <% if (SourceTable.Columns[i].Description != "") { %>--<%= SourceTable.Columns[i].Description %><% } %>
40<% } %>
41AS
42Delete From [<%= SourceTable.Name %>]
43Where
44<% for (int i = 0; i < SourceTable.PrimaryKey.MemberColumns.Count; i++) { %>
45<% if (i > 0) { %>AND <% } %>[<%= SourceTable.PrimaryKey.MemberColumns[i].Name %>] = @<%= SourceTable.PrimaryKey.MemberColumns[i].Name %>
46<% } %>
如果有问题我会尽力帮助大家解决的,共同提高^_^
本文永久地址: http://www.livebaby.cn/blog/u/meil/archives/2007/984.html
========
CodeSmith使用基础教程 四 — 控制台与属性编辑器
七、CodeSmith控制台指南。
很多人仅仅知道CodeSmith像一个图形应用程序,或者可能是一个Visual Studio的附件,但是通过CodeSmith的控制台应用程序还有好多其他的使用方法。控制台应用程序是很有价值的,因为可以通过它去生成脚本,或者其他一些自动工具。这篇文档的目的就是要告诉你怎样使用它的控制台应用程序并且如何去定义变量和参数。
Basic Usage
大多数情况下是用控制台应用程序来创建一个模板,一个属性文件,然后保存输出的文件。这有一个很好的例子介绍将合并模版的处理过程放到一个过程中,就像使用NAnt工具。
首先我们要确定完成一个什么样的模版,为这个模板创建一个什么样的XML属性文件。XML属性文件提供在执行模版是需要的各个属性。生成一个属性文件最简单的方法是在CodeSmith Explorer中打开一个模版,填写属性,点击生成按钮generate,然后再点击Save Property Set XML按钮。这个按钮会在点击完生成按钮后找到,在Save Output和Copy Output按钮旁边。然后系统提示输入保存XML属性文件的文件名,下面看一个ArrayList.cst模版创建的XML属性文件。
1
2
3
4 Public
5 PersonArray
6 Person
7 False
8 False
9 PersonID
10 int
11 True
12 False
13
14
就像看到的一样,也可以手动创建这个文件,但是使用CodeSmith Explorer会更简便。
现在我们有了这个XML文件,我们继续看一下如何去执行这个模版并是用控制台工具保存结果。首先我们需要是用/template参数去声明我们要是用的模版,像这样:
C:/Program Files/CodeSmith/v3.0>cs /template:Samples/Collections/ArrayList.cst
在这个例子中我们使用了ArrayList.cst模版,它存储在本地的Samples/Collections文件夹下。下一步我们要去声明我们在最后一步需要创建的XML文件,我们是用/propertyset参数去实现。
C:/Program Files/CodeSmith/v3.0>cs /template:Samples/Collections/ArrayList.cst /propertyset:PersonArray.xml
这个/property参数用来指定我们的XML属性文件。最后一个我们需要用的参数是/output参数,用来指定输出怎样被保存。
C:/Program Files/CodeSmith/v3.0>cs /template:Samples/Collections/ArrayList.cst /propertyset:PersonArray.xml /out:test.cs
使用/out参数指定将结果输出到一个叫test.cs文件中保存。执行这个命令后,模板将开始运行,使用属性文件将结果输出到test.cs文件保存。
这是大多数情况下有效使用控制台。
Merging Output
在各种代码生成中最大的挑战就是将生成的代码和开发人员编写或修改的代码区分开。控制台对这个问题提供了一个有效的独特的解决方案,使用一个指定的参数在当前已存在的代码文件中需要将模板生成的代码添加的地方指定一块区域。
下面是一个简单的代码文件,包含了我们要添加生成代码的区域。
1using System;
2
3namespace Entities
4{
5 GeneratedOrderEntity
9}
我们的目标是将DatabaseSchema/BusinessObject.cst模版生成的代码添加到类文件的GeneratedOrderEntity区域中。和上一个例子一样,使用CodeSmith console控制台应用程序执行这个模版,但是这次要使用另一个参数merge。
C:/Program Files/CodeSmith/v3.0>cs /template:Samples/DatabaseSchema/BusinessObject.cst /propertyset:OrderEntity.xml /out:OrderEntity.cs /merge:InsertRegion= "RegionName=Sample Generated Region;Language=C#;"
使用merge参数我们可以指定区域的名称,在这个例子中是GeneratedOrderEntity,然后控制台应用程序将执行模版,并将结果添加到这个区域中。我们来看一下执行完这个指令后生成的代码。
1using System;
2
3namespace Infozerk.AuthServices.UnitTestSuite
4{
5 GeneratedOrderEntity就像看到的一样,Order类被添加到了我们指定的区域中。在代码文件中使用merge参数生成的内容在其他部分被修改或手写后很容易重新再次生成而不会产生影响。
参数介绍Parameter Reference
Specifying Output
/out:
指定从模版创建的输出文件的名称。
/out:default
指定这个文件被默认保存成模版是用的名称。
/merge:=
指定模版输出的区域。可以简写为/m
Specifying Input
/template:
选择要执行的模版,简写为/t
/propertyset:
生成代码时需要使用的XML属性文件。简写为/p
Compiler Options
/debug[+|-]
指定模版需要包含的调试信息。(允许在运行模版时进行调试)
/tempfiles[+|-]
指定保留临时文件。(如果在临时文件上调试也可以)
Miscellaneous
/help
显示帮助信息。
/nologo
禁止生成器版权信息。
八、编写CodeSmith自定义属性的编辑器(Writing Custom Property Editors)
当你开始编写自定义的CodeSmith模板时,很可能对于使用它的strings或integers属性很满意,但有时你会发现需要创建一个不同类型的属性,可能是一个自定义的类型或者是.NET framework中但是在属性面板中没有提供的类型。在模板中去作这些很简单,但是怎样指定一个类型在运行模板时显示在属性面板中呢?例如创建了一个Person类并且具有很多不同的属性,但是却没有办法让用户去组装这个类……除非创建一个自定义属性编辑器。
属性面板提供了方法去编写自定义的属性编辑器,当用户在面板上选择一个属性时可以激发相应的方法,同时也可以通过编写代码实现提示用户输入一个必要的值。下面我们举个例子,创建一个接受组建的属性并且是用影射循环贯串所有的类,是所有的类都可以使用它和它的方法,去创建一个NUnit测试基础。(这句翻译的不好,原文:As an example we are going to build a template which accepts an assembly as a property and then using reflection loops through all of the classes, and the methods of those classes, to build NUnit test stubs.)
首先,我们来关注一下模板的组件属性,暂且不看自定义编写的代码。模板的第一部分是一些声明定义和属性。将属性放在脚本标签中代替使用属性声明,在下一部分将看到这样做的必要。
1<%@ CodeTemplate Language="C#" TargetLanguage="C#" Description="Builds a class for each class in the assembly, and a test stub for every method." %>
2
3<%@ Import NameSpace="System.Reflection" %>
4
5
然后我们为组建assembly中的每一个类创建一个类,为每一个类创建他的方法。然后直接将模板的输出内容放入Visual Studio.NET,然后在编写组件的单元测试时使用向导。
1using System;
2using NUnit.Framework;
3
4<%
5 foreach(Type T in AssemblyToLoad.GetTypes())
6 {
7 if(T.IsClass)
8 {
9 %>
10
11 [TestFixture]
12 public class <%=T.Name%>Tests
13 {
14 <%
15 MethodInfo[] methods = T.GetMethods ( BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static );
16 foreach(MethodInfo M in methods)
17 {
18 %>
19
20 [Test]
21 public void <%=M.Name%>Test
22 {
23 //TODO Write this test
24 }
25 <%
26 }
27
28 %>}<%
29 }
30 }
31%>
/Files/Bear-Study-Hard/AssemblyHelper.zip
首先我们需要创建一个继承UITypeEditor的类。
1public class AssemblyFilePicker : UITypeEditor
2{
3 public AssemblyFilePicker(): base()
4 {
5 }
6}
关于UITypeEditor的说明请大家参看MSDN或Visual Studio.NET自带帮助中的说明,其中有详细的例子。
然后我们需要重载UITypeEditor类的两个不同的方法。第一个需要重载点的方法是GetEditStyle,这个方法是告诉属性面板对于当前类型是用什么类型的编辑器,在这个例子中我们设置编辑类型为Modal。这样大家可以在该属性格子的右边看到一个小按钮,它将引发一个对话框等模式的对话(trigger a modal dialog)。这是我们的GetEditStyle方法:
1public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
2{
3 return UITypeEditorEditStyle.Modal;
4}
其中的Modal为显示一个省略号按钮。
首先我们要从当前的服务和控件中得到一个参考,有了控件的参考我们可以通过它转到ShowDialog方法。(原文:First we need to get a reference to the current service and control, we need the reference to the control so we can pass it to the ShowDialog method.) 然后我们创建一个openFileDialog类并填入适合的属性。 然后我们通过控件的参考(reference)将对话框显示给用户。 下一步我们检查用户是否点击了OK按钮,如果点击了,通过文件选择对话框选择文件后使用LoadForm方法加载这个组件,最后返回这个值。 这个值将被放在属性面板中并可以被模板读取,但是需要注意,在我们作这个之前要将组件import引入到模板中,并在模板中用一对属性声明。
1IWindowsFormsEditorService editorService = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
2Control editorControl = editorService as Control;
3
4if (editorControl != null)
5{
1OpenFileDialog openFileDialog = new OpenFileDialog();
2
3openFileDialog.CheckFileExists = true;
4openFileDialog.DefaultExt = ".dll";
5openFileDialog.Multiselect = false;
6openFileDialog.Title = "Select an Assembly:";
7openFileDialog.Filter = "Assembly Files | *.dll";
1DialogResult result = openFileDialog.ShowDialog(editorControl);
1if (result == DialogResult.OK)
2 {
3Assembly assembly = Assembly.LoadFrom( openFileDialog.FileName ) ;
4 value = assembly;
5 }
6 else
7 {
8 value = null;
9 }
10 }
11}
12
13return value;
14}
加载这个模板我们仅需将这个组件assembly与模板放在同一目录下,然后再模板中加入下面两行代码。
1<%@ Assembly Name="AssemblyHelper" %>
2<%@ Import NameSpace="AssemblyHelper" %>
需要重载的另一个方法是EditValue方法,当用户电击属性时会调用这个方法。按照我们需要加载的组件类型需要创建一个打开文件对话框(open file dialog)然后捕获这个对话框,在属性格子中返回对话框的结果。
1public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
2{
3
4if (provider != null)
5{
这个模板仅仅可以编译通过,但是由于我们编写显示了一个类型属性面板并不知道如何去操作它,所以我们没有办法自定义指定组件在加载时想要加载的组件。
我们需要创建一个UITypeEditor,这是一个建立属性面板是用的特殊属性的类。UITypeEditor需要创建在一个和模板分离的组件中,我们是用Visual Studio创建这个类。
本文永久地址: http://www.livebaby.cn/blog/u/meil/archives/2007/982.html
========
实例演示CodeSmith与ECC开发模式结合---快速建站(一)
http://blog.csdn.net/breakersam/article/details/1551935
前言
其实本文所说的思路产生以很久以前,本人也曾将用于多个小型项目开发之中,用下来的整体说还是比较满意。按理说,自己既然用了那么多次也应写些心得或是总结出来吧,无奈一是自己太懒二是文字功底有限,只好罢了!拖到了现在,方提指敲写,也不知成文怎样,由大家评说吧。
本文作为开发笔记以流水的方式敲写,其中不讨论开发模式之间的优劣;如大家有好的建议也希望直面地提出来,我呢,以求进步!
文中所举的例子: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生成后的代码存放。
如下
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的例子获得。
具体的码如下:
========
codesmith资料
http://www.cnblogs.com/Terrylee/archive/2005/12/28/306254.html
CodeSmith开发系列资料总结
http://www.tuicool.com/articles/2EbIra
CodeSmith自己动手写模板
http://www.cnblogs.com/whitewolf/archive/2010/09/27/1836729.html
CodeSmith模板引擎系列-目录
http://www.cnblogs.com/wintersun/p/3971072.html
软件代码生成之Codesmith模板.netTiers
http://www.cnblogs.com/knowledgesea/p/5016077.html
CodeSmith模板代码生成实战详解
http://blog.csdn.net/gxiangzi/article/details/6865619
CodeSmith .NET三层架构模板