CodeSmith 基础(转载)

摘自:努力学习的熊  codesmith基础 http://bear-study-hard.cnblogs.com/category/43725.html

CodeSmith基础(一)

        请大家耐心看完所有的基础文章,前两篇网上发表的比较多,是CodeSmith英文帮助文档的第一篇,我后面写的基础是将其他所有的英文帮助全部翻译出来了,全部为本人手写翻译,希望对大家有所帮助创建好一个模板后第一步要指明这是一个C#语言的模板。

<%@ CodeTemplate Language="C#" TargetLanguage="C#"
      Description
="Generates a class including a special informational header" %>

        第二步,我们要指明模板在生成代码时的属性,即生成代码需要的输入值变量。

<%@ Property Name="NameSpace" Type="String"    Category="Context"
      Description
="The namespace to use for this class" %>

        如上边所示,在进行代码生成时,在CodeSmith Explorer中选择模板后生成代码的窗口中,变量的名称为NameSpace,类型是String,类别是Context,当用户选中这个属性时对于属性的描述Description
       
我们可以按照C#语言的语法去使用定义的变量,例如:

// File: <%=ClassName%>.cs

        例如下面这个例子模板使用了上面介绍的知识。Test.cst

<%@ CodeTemplate Language="C#" TargetLanguage="C#"

      Description="Generates a class including a special informational header" %>

 

<%@ Property Name="Namespace" Type="String" Category="Context"

      Description="The namespace to use for this class" %>

<%@ Property Name="ClassName" Type="String"  Category="Context"

      Description="The name of the class to generate" %>

<%@ Property Name="Author" Type="String"  Category="Context"

      Description="The name to include in the comment header" %>

/////////////////////////////////////////////////////////////////////////

// File: <%=ClassName%>.cs

// Description: Enter summary here after generation.

// ---------------------

// Copyright ? <%= DateTime.Now.Year %>

// ---------------------

// History

//    <%= DateTime.Now.ToShortDateString() %>  Author:  <%= Author%>  

/////////////////////////////////////////////////////////////////////////

using System;

namespace <%=Namespace %>

{

  /// <summary>

  /// Summary description for <%=ClassName %>.

  /// </summary>

  public class <%=ClassName %>

  {

    public <%=ClassName %>(){

      //

      // TODO: Add constructor logic here

        

    }

  }}
然后我们在CodeSmith Explorer中双击这个模板就会看到相应的属性界面,这里的属性均是我们在前边定义的属性。


/////////////////////////////////////////////////////////////////////////

// File: Order.cs

// Description: Enter summary here after generation.

// ---------------------

// Copyright ? 2006

// ---------------------

// History

//    2006-6-19  Author:  Neil  

/////////////////////////////////////////////////////////////////////////

 

using System;

namespace com.fjlib

{

  /// <summary>

  /// Summary description for Order.

  /// </summary>

  public class Order

  {

    public Order(){

      //

      // TODO: Add constructor logic here

       

    }

  }

}

CodeSmith基础(二)

        本文将介绍CodeSmith与数据库进行交互生成相应的存储过程,本例使用的数据库为SQL Server 2000。在与数据库进行交互时,我们使用到了一个CodeSmith自带的组件SchemaExplorer,利用这个组件我们可以访问数据库的数据表、存储过程、视图等,并可以得到相应的数据类型、标识列、列的(字段)名称等信息。
       
下面这个例子是教我们如何生成一个存储过程,虽然网上有很多一样的例子,但是我是从CodeSmith中的英文帮助中自己翻译出来的:)
       
使用的是SQL Server 2000自带的Northwind数据库,生成一个关于Orders订单表的更新存储过程。
       
第一步还是指明模板使用的语言和生成的目标语言。

<%@ CodeTemplate Language="C#" TargetLanguage="T-SQL" Description="Generates a update stored procedure." %>
       
第二步就是我们要加载使用访问数据库的组件SchemaExplorer,并声明其使用的命名空间。

<%@ Assembly Name="SchemaExplorer" %>
<%@ Import Namespace="SchemaExplorer" %>

        因为是针对表去生成存储过程,则首先要定义一个存储表名称使用的变量,然后指明这个变量类型为数据库中的表,这样我们可以通过这个数据表类型的变量得到相应的表的信息。

<%@ Property Name="SourceTable" Type="SchemaExplorer.TableSchema" Category="Context"  Description="Table that the stored procedures should be based on." %>

        如果想访问视图的话,则将变量类型Type中的SchemaExplorer.TableSchema修改为SchemaExplorer.ViewSchema即可。
        
得到表名的方法

CREATE PROCEDURE dbo.Update<%= SourceTable.Name %>


       
下面利用循环语句遍历表的各个列,拼出存储过程需要传递的参数。

<% for (int i = 0; i < SourceTable.Columns.Count; i++) { %>
<%= GetSqlParameterStatement(SourceTable.Columns[i]) %><% 
if (i < SourceTable.Columns.Count - 1) { %>,<% } %>
<% } %>


       
调用的GetSqlParameterStatement方法是用来生成参数的字符串,例如生成@CustomerID nchar(5)”,后边紧跟的if判断是用来生成参数之间相隔使用的逗号的。
       
生成参数字符串的方法,参数为SchemaExplorer.ColumnSchema列类型

 1 <script runat="template">
 2 public string GetSqlParameterStatement(ColumnSchema column)
 3 {
 4       string param = "@" + column.Name + " " + column.NativeType; 5  
 6       switch (column.DataType)
 7       {
 8             case DbType.Decimal:
 9             {
10                   param += "(" + column.Precision + ", " + column.Scale + ")";
11                   break;
12             }
13             default:
14             {
15                   if (column.Size > 0)
16                   {
17                         param += "(" + column.Size + ")";
18                   }
19                   break;
20             }
21       }
22        return param;
24 }
25 </script>


       
下面来生成需要更新的字段,更新时仅能更新非主键字段的值,在SchemaExplorer中支持这种区别,使用SourceTable.NonPrimaryKeyColumns即可得到非主键字段的集合。

1 UPDATE [<%= SourceTable.Name %>] SET
2       <% for (int i = 0; i < SourceTable.NonPrimaryKeyColumns.Count; i++) { %>
3       [<%= SourceTable.NonPrimaryKeyColumns[i].Name %>= @<%= SourceTable.NonPrimaryKeyColumns[i].Name %><% if (i < SourceTable.NonPrimaryKeyColumns.Count - 1) { %>,<% } %>
4       <% } %>

    然后再使用SourceTable.PrimaryKey.MemberColumns得到数据表中的主键集合,生成更新条件

1 WHERE
2    <% for (int i = 0; i < SourceTable.PrimaryKey.MemberColumns.Count; i++) { %>
3       <% if (i > 0) { %>AND <% } %>
4       [<%= SourceTable.PrimaryKey.MemberColumns[i].Name %>= @<%= SourceTable.PrimaryKey.MemberColumns[i].Name %>
5       <% } %>


   
以下为整体的代码结构

 1 <%@ CodeTemplate Language="C#" TargetLanguage="T-SQL"
 2       Description="Generates a update stored procedure." %>
 3  
 4 <%@ Property Name="SourceTable" Type="SchemaExplorer.TableSchema"
 5     Category="Context"
 6     Description="Table that the stored procedures should be based on." %>
 7  
 8 <%@ Assembly Name="SchemaExplorer" %>
 9 <%@ Import Namespace="SchemaExplorer" %>
11       
12 <script runat="template">
13 public string GetSqlParameterStatement(ColumnSchema column)
14 {
15       string param = "@" + column.Name + " " + column.NativeType;
16       switch (column.DataType)
18       {
19           case DbType.Decimal:
20           {
21               param += "(" + column.Precision + ", " + column.Scale + ")";
22               break;
23           }
24             default:
25             {
26                   if (column.Size > 0){
28                         param += "(" + column.Size + ")";
29                   }
30                   break;
31             }
32       }33  
34       return param;
35 }
36 </script>
37  
38 -----------------------------------------------------------------
39 -- Date Created: <%= DateTime.Now.ToLongDateString() %>
40 -- Created By:   Generated by CodeSmith
41 -----------------------------------------------------------------
42  CREATE PROCEDURE dbo.Update<%= SourceTable.Name %>
44       <% for (int i = 0; i < SourceTable.Columns.Count; i++) { %>
45       <%= GetSqlParameterStatement(SourceTable.Columns[i]) %><% if (i < SourceTable.Columns.Count - 1) { %>,<% } %>
46       <% } %>
47 AS
49 UPDATE [<%= SourceTable.Name %>] SET
50       <% for (int i = 0; i < SourceTable.NonPrimaryKeyColumns.Count; i++) { %>
51       [<%= SourceTable.NonPrimaryKeyColumns[i].Name %>] = @<%= SourceTable.NonPrimaryKeyColumns[i].Name %><% if (i < SourceTable.NonPrimaryKeyColumns.Count - 1) { %>,<% } %>
52       <% } %>
53 WHERE
54   <% for (int i = 0; i < SourceTable.PrimaryKey.MemberColumns.Count; i++) { %>
55       <% if (i > 0) { %>AND <% } %>
56       [<%= SourceTable.PrimaryKey.MemberColumns[i].Name %>] = @<%= SourceTable.PrimaryKey.MemberColumns[i].Name %>
57       <% } %>
58 

CodeSmith基础(三)

        这里写的东东都是从CodeSmith自带的帮助文档中FAQ里学到的东东
        1
.如何在模板中添加注释
        CodeSmith

        <%-- Comments --%>
        VB.NET

        <%-- 'Comments --%>
        C#

        <%-- // Comments --%>
        <%-- /* Comments */ --%>

        2
.创建一个可以下拉选择的属性
       
首先定义一个枚举类型的变量,然后将属性的类型设置为枚举型

 1 <%@ Property Name="CollectionType" Type="CollectionTypeEnum" Category="Collection" Description="Type of collection" %>
 2 
 3 <script runat="tempate">
 4 public enum CollectionTypeEnum
 5 {
 6     Vector,
 7     HashTable,
 8     SortedList
 9 }
10 </script>


        3
.解决ASP.NET中标签<%重复问题
       
先将ASP.NET中使用的这个重复标签写成<%%,避免在生成代码时由于是标签重复引起的编译错误或生成错误。

        4
.如何声明一个常量       

<script runat="template">
private const string MY_CONST = "example"; 
</script>


        5
.如何对模板进行调试
       
如果要调试一个模板,首先要在代码模板里进行声明,然后在你想要进行调试的地方用Debugger.Break()语句设置断点即可。

<%@ CodeTemplate Language="C#" TargetLanguage="T-SQL" Description="Debugging your template" Debug="true" %>

<% Debugger.Break(); %>


        6
.如何将属性设置成选择一个文件夹的路径

[Editor(typeof(System.Windows.Forms.Design.FolderNameEditor), typeof(System.Drawing.Design.UITypeEditor))]
public string OutputDirectory
{
      
get {return _outputDirectory;}
      
set {_outputDirectory= value;}
}


        7
.怎样调用子模板

 1 <% 
 2 foreach (TableSchema table in SourceDatabase.Tables) 
 3
 4    OutputSubTemplate(table); 
 5
 6 %>
 7 <script runat="template"> 
 8 private CodeTemplate _mySubTemplate;
 9
10 [Browsable(false)]
11 public CodeTemplate MySubTemplate 
12
13    get 
14    
15       if (_mySubTemplate == null
16       
17          CodeTemplateCompiler compiler = new CodeTemplateCompiler(this.CodeTemplateInfo.DirectoryName + "MySubTemplate.cst"); 
18          compiler.Compile(); 
19          if (compiler.Errors.Count == 0) 
20          
21             _mySubTemplate = compiler.CreateInstance(); 
22          } 
23          else 
24          
25             for (int i = 0; i < compiler.Errors.Count; i++) 
26              {
27                Response.WriteLine(compiler.Errors[ i].ToString()); 
28             } 
29          } 
30       } 
31       return _mySubTemplate; 
32    } 
33 }
34
35 public void OutputSubTemplate(TableSchema table) 
36
37    MySubTemplate.SetProperty("SourceTable", table); 
38    MySubTemplate.SetProperty("IncludeDrop", false); 
39    MySubTemplate.SetProperty("InsertPrefix", "Insert"); 
40    MySubTemplate.Render(Response); 
41
42 </script>

        FAQ中给出的例子为生成一个数据库中所有表的更新Update存储过程
        SubTemplatesExample.cst
文件源代码

 1 <%@ CodeTemplate Language="C#" TargetLanguage="T-SQL"
 2     Description="Generates a update stored procedure." %>
 3
 4 <%@ Property Name="SourceDatabase" Type="SchemaExplorer.DatabaseSchema"
 5     Category="Context"
 6     Description="Database" %>
 7
 8 <%@ Assembly Name="SchemaExplorer" %>
 9
10 <%@ Import Namespace="SchemaExplorer" %>
11
12 <% 
13 foreach (TableSchema table in SourceDatabase.Tables) 
14
15    OutputSubTemplate(table); 
16
17 %> 
18
19 <script runat="template"> 
20 private CodeTemplate _mySubTemplate; 
21  
22
23   
24
25 [Browsable(false)]
26 public CodeTemplate MySubTemplate 
27
28    get 
29    
30       if (_mySubTemplate == null
31       
32          CodeTemplateCompiler compiler = new CodeTemplateCompiler(this.CodeTemplateInfo.DirectoryName + "MySubTemplate.cst"); 
33          compiler.Compile(); 
34          
35          if (compiler.Errors.Count == 0) 
36          
37             _mySubTemplate = compiler.CreateInstance(); 
38          } 
39          else 
40          
41             for (int i = 0; i < compiler.Errors.Count; i++) 
42              {
43                Response.WriteLine(compiler.Errors[ i].ToString()); 
44             } 
45          } 
46       } 
47       
48       return _mySubTemplate; 
49    } 
50
51
52 public void OutputSubTemplate(TableSchema table) 
53
54    MySubTemplate.SetProperty("SourceTable", table); 
55    MySubTemplate.SetProperty("IncludeDrop", false); 
56    MySubTemplate.SetProperty("InsertPrefix", "Insert"); 
57    
58    MySubTemplate.Render(Response); 
59
60 </script>

        MySubTemplate.cst文件源代码

 1 <%@ CodeTemplate Language="C#" TargetLanguage="T-SQL"
 2     Description="Generates a update stored procedure." %>
 3
 4 <%@ Property Name="SourceTable" Type="SchemaExplorer.TableSchema"
 5     Category="Context"
 6     Description="Table that the stored procedures should be based on." %>
 7
 8 <%@ Assembly Name="SchemaExplorer" %>
 9
10 <%@ Import Namespace="SchemaExplorer" %>
11     
12     
13 <script runat="template">
14 public string GetSqlParameterStatement(ColumnSchema column)
15 {
16     string param = "@" + column.Name + " " + column.NativeType;
17
18     switch (column.DataType)
19      {
20         case DbType.Decimal:
21          {
22             param += "(" + column.Precision + ", " + column.Scale + ")";
23             break;
24         }
25         default:
26          {
27             if (column.Size > 0)
28              {
29                 param += "(" + column.Size + ")";
30             }
31             break;
32         }
33     }
34
35     return param;
36 }
37 </script>
38
39 -----------------------------------------------------------------
40 -- Date Created: <%= DateTime.Now.ToLongDateString() %>
41 -- Created By:   Generated by CodeSmith
42 -----------------------------------------------------------------
43
44 CREATE PROCEDURE dbo.Update<%= SourceTable.Name %>
45     <% for (int i = 0; i < SourceTable.Columns.Count; i++)  { %>
46     <%= GetSqlParameterStatement(SourceTable.Columns[i]) %><% if (i < SourceTable.Columns.Count - 1)  { %>,<% } %>
47     <% } %>
48 AS
49
50 UPDATE [<%= SourceTable.Name %>] SET
51     <% for (int i = 0; i < SourceTable.NonPrimaryKeyColumns.Count; i++)  { %>
52     [<%= SourceTable.NonPrimaryKeyColumns[i].Name %>] = @<%= SourceTable.NonPrimaryKeyColumns[i].Name %><% if (i < SourceTable.NonPrimaryKeyColumns.Count - 1)  { %>,<% } %>
53     <% } %>
54 WHERE
55     <% for (int i = 0; i < SourceTable.PrimaryKey.MemberColumns.Count; i++)  { %>
56     <% if (i > 0)  { %>AND <% } %>
57     [<%= SourceTable.PrimaryKey.MemberColumns[i].Name %>] = @<%= SourceTable.PrimaryKey.MemberColumns[i].Name %>
58     <% } %>


        8
.在加载模板时默认加载的命名空间Namespaces和组件Assemblies
       
组件:mscorlib, System, System.Xml, System.Data, System.Drawing, Microsoft.VisualBasic, System.Windows.Forms, CodeSmith.Engine
       
命名空间:System, System.Data, System.Diagnostics, System.ComponentModel, Microsoft.VisualBasic, CodeSmith.Engine

        9
.使用SchemaExplorer能否确定一个字段(Field)是标识字段(主键,Identity Field
       
在字段的扩展属性集合中包含一个叫“CS_IsIdentity”的属性,如果这个属性的值为true,则表名当前字段为一个标识字段

1 Identity Field = <% foreach(ColumnSchema cs in SourceTable.Columns) {  
2       if( ((bool)cs.ExtendedProperties["CS_IsIdentity"].Value) == true)
3       {
4             Response.Write(cs.Name);
5       }
6 }
7 %>

        CS_Identity_Example.cst文件源代码

 1 <%@ CodeTemplate Language="C#" TargetLanguage="T-SQL"
 2     Description="Identifies the identity field of a table" %>
 3 
 4 <%@ Property Name="SourceTable" Type="SchemaExplorer.TableSchema"
 5     Category="Context"
 6     Description="Table to target." %>
 7 
 8 <%@ Assembly Name="SchemaExplorer" %>
 9 
10 <%@ Import Namespace="SchemaExplorer" %>
11 
12 
13 
14 Identity Field = <% foreach(ColumnSchema cs in SourceTable.Columns) {  
15                         if( ((bool)cs.ExtendedProperties["CS_IsIdentity"].Value) == true)
16                         {
17                             Response.Write(cs.Name);
18                         }
19                     }
20                  %>

        10.如何确定一个字段的默认值(各人认为翻译成如何知道一个字段有默认值并且默认值是什么)
       
在字段的扩展属性集合中包含一个叫“CS_Default”的属性

1 <%
2 foreach(ColumnSchema cs in SourceTable.Columns) {  
3       if (cs.ExtendedProperties["CS_Default"] != null)
4       {
5            Response.WriteLine(cs.ExtendedProperties["CS_Default"].Value);
6       }
7 }
8 %>


        11
.如何使用SchemaExplorer得到存储过程的输入输出参数
       
使用CodeSmith提供的CommandSchema对象,它包含需要的输入输出参数集合

 1 Input Parameters: 
 2 <%foreach(ParameterSchema ps in SourceProcedure.AllInputParameters)
 3 {
 4       Response.Write(ps.Name);
 5       Response.Write("\n");
 6 }
 7 %>
 8 
 9 
10 Output Parameters: 
11 <%foreach(ParameterSchema ps in SourceProcedure.AllOutputParameters)
12 {
13       Response.Write(ps.Name);
14       Response.Write("\n");
15 }
16 %>

        InputOutputParameterExample.cst文件源代码

 1 <%@ CodeTemplate Language="C#" TargetLanguage="T-SQL"
 2     Description="Generates a update stored procedure." %>
 3 
 4 <%@ Property Name="SourceProcedure" Type="SchemaExplorer.CommandSchema"
 5     Category="Context"
 6     Description="The stored procedure to examine" %>
 7 
 8 <%@ Assembly Name="SchemaExplorer" %>
 9 
10 <%@ Import Namespace="SchemaExplorer" %>
11 
12 Input Parameters: 
13 <%foreach(ParameterSchema ps in SourceProcedure.AllInputParameters)
14 {
15     Response.Write(ps.Name);
16     Response.Write("\n");
17 }
18 %>
19 
20 
21 Output Parameters: 
22 <%foreach(ParameterSchema ps in SourceProcedure.AllOutputParameters)
23 {
24     Response.Write(ps.Name);
25     Response.Write("\n");
26 }
27 %>

Template="MySubTemplate.cst" MergeProperties="True" ExcludeProperties="SomeExcludedPropertyName,SomeProperties*" %>

    模版一旦被注册,就可以建立一个模版的实例,然后象这样设置它的属性:

 1 <script runat="template">
 2 public void OutputSubTemplate()
 3 {
 4    MySubTemplate mySubTemplate = new MySubTemplate();
 6    // set an individual properties value.
 7    mySubTemplate.SomeExcludedPropertyName = "SomeValue";
 9    // copy all properties with matching name and type to the sub template instance.
10    this.CopyPropertiesTo(mySubTemplate);
12    // render the template to the current templates Response object.
13    mySubTemplate.Render(this.Response);
15    // render the template to a file.
16    mySubTemplate.RenderToFile("C:\SomeFile.txt");
17 }
18 </script>

注册的参数:
    Name
:代表被引入的模版的名称。它可以被用作创建一个模版的实例。
    Template
:被引入模版文件的相对路径,它可以与当前的模版一起被动态的编译。
    MergeProperties
:设置成True时,所有被引用的面板的属性将被动态的添加到当前模版中。
    ExcludePorperties
:当使用MergeProperties时,你可能不需要某些属性被添加到当前模版中。将不需要的属性以逗号分隔放在这里,*号可以被用作通配符使用。

组件的声明(Assembly Directive
    用作在模版中引用一个外部部组件,或者包含一个编译好的源文件。
例:

<%@ Assembly Name="SchemaExplorer" %>

<%@ Assembly Src="MySourceFile.cs" %>

    CodeSmith自动加载一些不同的组件:System, System.Diagnostics, System.ComponentModel, Microsoft.VisualBasic, CodeSmith.Engine

组件的参数:
    Name
:需要引用组件的名称,组建必须存在于Global Assembly Cache,与CodeSmith在同一路径下或与模版文件在同一路径下。
    Src
:要包含文件的相对路径。

引入的声明(Import Directive
    在模版中引入一个命名空间,这个与VB.NET中的ImportsC#中的using相同。
   
例:

<%@ Import Namespace="SchemaExplorer" %>

引入的参数:
    NameSpace
:被引入的命名空间的名字。记住同时必须要加载包含这个命名空间的相应组件,除非这个组件是被默认加载的。

CodeSmith基础(五)

Posted on 2005-12-21 13:35 努力学习的熊 阅读(661) 评论(1)  编辑 收藏 收藏至365Key 所属分类: CodeSmith使用

       本篇将介绍CodeSmith的模版中的语法。
代码标签
       <% %>
标签
      
可以放置任意数量的代码在其中,但并不能直接输出到模版中。

<% foreach (ColumnSchema column in SourceTable.Columns) { %>
<%= column.Name %>
<% } %>

<%= %>标签

在模版中输出一个字符串。上例中的<%=column.Name%>

脚本标签

在这个标签中可以包含一段代码,但是他不直接影响输出的模版。可以放置一些比较有帮助的方法在其中,然后在模版的各个地方可以调用它。在脚本标签中必须包含这个参数runat=”template”,否则他会被处理成普通文本。

例:

 1 <script runat="template">
 2 private string GetColumnName(ColumnSchema cs)
 3 {
 4       return cs.Name;
 5 }
 6 </script>
 7 
 8 <% foreach (ColumnSchema cs in SourceTable.Columns) { %>
 9 <%= GetColumnName(cs) %>
10 <% } %>

使用标签可以大量减少代码,并使模版更加的易读和一管理。

Include标签

ASP.NET一样,可以在模版中包含一些文本文件,但同ASP.NET一样它也不是总能达到你的目标。

例:

<!-- #include file="myfile.inc" -->

有时在多个模版中引用一个组件中的功能,调用其中的方法,这时我们引用组件。但有些情况下,适用Include标签可以得到更好的效果。

Comment标签

注释标签,在前边已经做过介绍。

例:

<%-- This is a comment --%>

 

CodeSmith基础(六)

       本文主要介绍CodeSmith对象。

       CodeSmith Object
       CodeSimth
中有许多对象可以在编写模板的时候使用,这里将介绍这些对象的一些公用方法和属性以及怎么使用它们。
 

代码模板对象(CodeTemplate Object
在模板中,“this”(或者“Me”VB.NET中)在当前模板中代码代码模板对象。 

代码模板的方法(CodeTemplate Methods

1
public virtual void GetFileName()
可以重载这个方法设置模板输出到文件的名称。否则CodeSmith将基于模板名称和TargetLanguage设置它的文件名。

2public void CopyPropertiesTo(CodeTemplate target)
这个方法可以实现从一个模板中将其所有属性的值拷贝到另一个模板所有对应属性中,并按照相应的属性值类型进行匹配。

3public object GetProperty(string propertyName)
这个方法将返回一个给定名称的属性的值。

4public void SetProperty(string propertyName, object value)
此方法可以根据给定名称的属性设置其值。

5public string SavePropertiesToXml ()
这个方法将现有的属性值保存成一个XML的属性字符串。

6public void SavePropertiesToXmlFile (string fileName)
这个方法将当前属性值保存成一个XML的属性文件。

7public void RestorePropertiesFromXml(string propertySetXml, string baseDirectory)
从保存在XML文件中的属性字符串,将模板的属性值恢复。

8public void RestorePropertiesFromXmlFile(string fileName)
从保存在XML文件中的属性文件,将模板的属性值恢复。 

代码模板的属性(CodeTemplate Properties
Response:此属性可以访问当前的TextWriter对象,这个对象是用来输出模板用的。

CodeTemplateInfo:这个属性用来访问当前的CodeTemplateInfo对象,这个对象包含当前模板的一些信息。

Progress:这个属性用来报告当前模板的执行过程。

 

Response Object
这个对象提供直接写输出模板的方法。与ASP.NETresponse对象很相似。下面是一个利用ResponseWrite方法在模板上输出一段文字的例子。

<% Response.Write("This will appear in the template") %>

IndentLevel (Int32)
当使用Response对象时输出文本的缩进级别。

Indent() Method
将输出缩进一个级别。

Unindent() Method
将输出少缩进一个级别。

AddTextWriter(TextWriter writer) Method
Response对象增加一个TextWriter。这样可以使在同一时间用多个TextWriter输出模板。

 

CodeTemplateInfo Object
此对象包含一些当前模板的信息。下面是一些CodeTemplateInfo可用的属性。

DateCreated (DateTime)
返回一个date类型值,是模板创建的时间。

DateModified (DateTime)
返回模板最后一次被修改的时间。

Description (string)
返回模板声明时对模版的描述信息。

DirectoryName (string)
返回当前模板文件所在的路径。

FileName (string)
返回当前模版文件的文件名称。

FullPath (string)
返回当前模板的完整路径,路径名+文件名。

Language (string)
返回代码模版声明时使用的语言。

TargetLanguage (string)
返回代码模版声明时生成的目标语言。

 

Progress Object

这个属性用来报告当前模板的执行过程。下面是一些Progress可用的成员。

MaximumValue (Int32)
模版progress允许的最大值。

MinimumValue (Int32)
模版progress允许的最小值。

Step (Int32)
模版每执行一不progress的增长值。

Value (Int32)
Progress的当前值。

PerformStep() Method
按照指定好的progress的增加值执行一步。(原文:Perform a progress step incrementing the progress value by the amount specified in the Step property.

Increment(Int32 amount) Method
指定progress的增加值。(原文:Increment the progress value by the specified amount.

OnProgress (ProgressEventHandler) Event
这个事件用来报告模版的执行过程。(原文:This event can be used to be notified of template execution progress.

1 this.Progress.OnProgress += new ProgressEventHandler(this.OnProgress);
3 public void OnProgress(object sender, ProgressEventArgs e)
4 {
5   Trace.WriteLine(e.Value);
6 }

CodeSmith基础(七)

Posted on 2005-12-23 12:38 努力学习的熊 阅读(603) 评论(6)  编辑 收藏 收藏至365Key 所属分类: CodeSmith使用

本文翻译的内容为CodeSmith控制台指南。

很多人仅仅知道CodeSmith像一个图形应用程序,或者可能是一个Visual Studio的附件,但是通过CodeSmith的控制台应用程序还有好多其他的使用方法。控制台应用程序是很有价值的,因为可以通过它去生成脚本,或者其他一些自动工具。这篇文档的目的就是要告诉你怎样使用它的控制台应用程序并且如何去定义变量和参数。

Basic Usage

大多数情况下是用控制台应用程序来创建一个模板,一个属性文件,然后保存输出的文件。这有一个很好的例子介绍将合并模版的处理过程放到一个过程中,就像使用NAnt工具。

首先我们要确定完成一个什么样的模版,为这个模板创建一个什么样的XML属性文件。XML属性文件提供在执行模版是需要的各个属性。生成一个属性文件最简单的方法是在CodeSmith Explorer中打开一个模版,填写属性,点击生成按钮generate,然后再点击Save Property Set XML按钮。这个按钮会在点击完生成按钮后找到,在Save OutputCopy Output按钮旁边。然后系统提示输入保存XML属性文件的文件名,下面看一个ArrayList.cst模版创建的XML属性文件。

 1 <?xml version="1.0" encoding="us-ascii"?>
 2 <codeSmith>
 3             <propertySet>
 4                         <property name="Accessibility">Public</property>
 5                         <property name="ClassName">PersonArray</property>
 6                         <property name="ItemType">Person</property>
 7                         <property name="ItemValueType">False</property>
 8                         <property name="ItemCustomSearch">False</property>
 9                         <property name="KeyName">PersonID</property>
10                         <property name="KeyType">int</property>
11                         <property name="IncludeInterfaces">True</property>
12                         <property name="IncludeNamespaces">False</property>
13             </propertySet>
14 </codeSmith>

就像看到的一样,也可以手动创建这个文件,但是使用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

在各种代码生成中最大的挑战就是将生成的代码和开发人员编写或修改的代码区分开。控制台对这个问题提供了一个有效的独特的解决方案,使用一个指定的参数在当前已存在的代码文件中需要将模板生成的代码添加的地方指定一块区域。

下面是一个简单的代码文件,包含了我们要添加生成代码的区域。

1 using System;
3 namespace Entities
4  {   GeneratedOrderEntity#region GeneratedOrderEntity
6  
7
8       #endregion  
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,然后控制台应用程序将执行模版,并将结果添加到这个区域中。我们来看一下执行完这个指令后生成的代码。

 1 using System; 

 3 namespace Infozerk.AuthServices.UnitTestSuite
 4 {
 5       GeneratedOrderEntity#region GeneratedOrderEntity
 6       
 7
 8       Order#region Order
 9       /**//// <summary>
10       /// This object represents the properties and methods of a Order.
11       /// </summary>
12       public class Order
13        {
14             protected int _id;
15             protected string _customerID = String.Empty;
16             protected int _employeeID;
17             protected DateTime _orderDate;
18             protected DateTime _requiredDate;
19             protected DateTime _shippedDate;
20             protected int _shipVia;
21
22 --
为了简短省略了类的其他部分

就像看到的一样,Order类被添加到了我们指定的区域中。在代码文件中使用merge参数生成的内容在其他部分被修改或手写后很容易重新再次生成而不会产生影响。

 参数介绍Parameter Reference

 Specifying Output

/out:<file>

指定从模版创建的输出文件的名称。

/out:default

指定这个文件被默认保存成模版是用的名称。

/merge:<mergetype>=<init>

指定模版输出的区域。可以简写为/m

 

Specifying Input

/template:<file>

选择要执行的模版,简写为/t

/propertyset:<file>

生成代码时需要使用的XML属性文件。简写为/p

 Compiler Options

/debug[+|-]

指定模版需要包含的调试信息。(允许在运行模版时进行调试)

/tempfiles[+|-]

指定保留临时文件。(如果在临时文件上调试也可以)

 Miscellaneous

/help   显示帮助信息。

/nologo   禁止生成器版权信息。

CodeSmith基础(八)

        编写CodeSmith自定义属性的编辑器(Writing Custom Property Editors

        当你开始编写自定义的CodeSmith模板时,很可能对于使用它的stringsintegers属性很满意,但有时你会发现需要创建一个不同类型的属性,可能是一个自定义的类型或者是.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.

      首先,我们来关注一下模板的组件属性,暂且不看自定义编写的代码。模板的第一部分是一些声明定义和属性。将属性放在脚本标签中代替使用属性声明,在下一部分将看到这样做的必要。<%@ CodeTemplate Language="C#" TargetLanguage="C#" Description="Builds a class for each class in the assembly, and a test stub for every method." %>
 3 <%@ Import NameSpace="System.Reflection" %>
 5 <script runat="template">
 7 private Assembly assembly;
 9 public Assembly AssemblyToLoad
10 {
11       get {return assembly;}
12       set {assembly = value;}
13 }
15 </script>

        然后我们为组建assembly中的每一个类创建一个类,为每一个类创建他的方法。然后直接将模板的输出内容放入Visual Studio.NET,然后在编写组件的单元测试时使用向导。

 1 using System;
 2 using NUnit.Framework;
 3 <%
 5       foreach(Type T in AssemblyToLoad.GetTypes())
 6        {
 7             if(T.IsClass)
 8              {
 9                   %>

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 %>

        这个模板仅仅可以编译通过,但是由于我们编写显示了一个类型属性面板并不知道如何去操作它,所以我们没有办法自定义指定组件在加载时想要加载的组件。

        我们需要创建一个UITypeEditor,这是一个建立属性面板是用的特殊属性的类。UITypeEditor需要创建在一个和模板分离的组件中,我们是用Visual Studio创建这个类。

 /Files/Bear-Study-Hard/AssemblyHelper.zip

        首先我们需要创建一个继承UITypeEditor的类。

1 public class AssemblyFilePicker : UITypeEditor
2 {
3       public AssemblyFilePicker(): base()
4        {
5       }
6 }

        关于UITypeEditor的说明请大家参看MSDNVisual Studio.NET自带帮助中的说明,其中有详细的例子。

        然后我们需要重载UITypeEditor类的两个不同的方法。第一个需要重载点的方法是GetEditStyle,这个方法是告诉属性面板对于当前类型是用什么类型的编辑器,在这个例子中我们设置编辑类型为Modal。这样大家可以在该属性格子的右边看到一个小按钮,它将引发一个对话框等模式的对话(trigger a modal dialog)。这是我们的GetEditStyle方法:

1 public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) 
2 {
3       return UITypeEditorEditStyle.Modal;
4 }

        其中的Modal为显示一个省略号按钮。

        需要重载的另一个方法是EditValue方法,当用户电击属性时会调用这个方法。按照我们需要加载的组件类型需要创建一个打开文件对话框(open file dialog)然后捕获这个对话框,在属性格子中返回对话框的结果。

1 public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
2 {
3
4 if (provider != null
5 {

        首先我们要从当前的服务和控件中得到一个参考,有了控件的参考我们可以通过它转到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.

1 IWindowsFormsEditorService editorService = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
2 Control editorControl = editorService as Control;
3
4 if (editorControl != null
5 {

        然后我们创建一个openFileDialog类并填入适合的属性。

1 OpenFileDialog openFileDialog = new OpenFileDialog();                         
2
3 openFileDialog.CheckFileExists = true;
4 openFileDialog.DefaultExt = ".dll";
5 openFileDialog.Multiselect = false;
6 openFileDialog.Title = "Select an Assembly:";
7 openFileDialog.Filter = "Assembly Files | *.dll";

        然后我们通过控件的参考(reference)将对话框显示给用户。

1 DialogResult result = openFileDialog.ShowDialog(editorControl);

        下一步我们检查用户是否点击了OK按钮,如果点击了,通过文件选择对话框选择文件后使用LoadForm方法加载这个组件,最后返回这个值。

 1 if (result == DialogResult.OK)
 2              {
 3 Assembly assembly = Assembly.LoadFrom( openFileDialog.FileName ) ;
 4                   value = assembly; 
 5             }
 6             else
 7              {
 8                   value = null;
 9             }
10       }
11 }
12
13 return value;
14 }

        这个值将被放在属性面板中并可以被模板读取,但是需要注意,在我们作这个之前要将组件import引入到模板中,并在模板中用一对属性声明。

        加载这个模板我们仅需将这个组件assembly与模板放在同一目录下,然后再模板中加入下面两行代码。

1 <%@ Assembly Name="AssemblyHelper" %>
2 <%@ Import NameSpace="AssemblyHelper" %>

        然后我们要在组建属性中添加Editor属性,并且指定为UITypeEditor编辑器。

[Editor(typeof(AssemblyHelper.AssemblyFilePicker), typeof(System.Drawing.Design.UITypeEditor))]
2 public Assembly AssemblyToLoad
3 {
4       get {return assembly;}
5       set {assembly = value;}
6 }

        当属性面板读取到这些属性时,它将使用我们自定义的UITypeEditor编辑器并允许用户从打开文件对话框中选择一个组件。

 

 

 

 

CodeSmith的基础模版类(CodeSmith help中的内容)

基础模版类
类型描述:
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   
重载,保存指定的属性值

posted on 2006-06-20 11:10  灵风  阅读(1551)  评论(1编辑  收藏  举报