原文信息 - 原文地址
- 原文作者信息
- Justin Greenwood
- MyGeneration Software
- http://www.mygenerationsoftware.com/
- October 7, 2004
系统需求: - Microsoft Windows 2000/XP
- Microsoft .Net Framework 1.1/更高
- MDAC 2.7/更高
- MyGeneration
概观 MyGeneration目前使用了两种脚本引擎,一个是Microsoft Scripting Engine,它提供了JScript和VBScript的生成支持;另一个是 DotNetScript ,它提供了 VB.NET 和 C# 的支持。 DotNetScript 不像Microsoft Scripting Control那样的真正的脚本。实际上,它在运行时编译代码,然后利用编译后的.NET Assembly执行代码。这个教程通过例子说明使用 DotNetScript 开发MyGeneration模板的赞成与反对的理由。在这个例子中,我将使用C#和MS SQL中附带的Northwind数据库。
创建一个新的C#模板 - 打开MyGeneration
- 通过File->New->C# Template创建一个新的模板
- 点击属性按钮编辑模板的属性
- 如下图,填充模板的属性
- 保存模板
研究默认的模板代码默认的模板主体代码: 不像 JScript 或VBScript,C#的的模板代码相对较少。这个默认的代码是非常重要的。一个C#模板必须有一个继承了 DotNetScriptTemplate 的名为 GeneratedTemplate 的类。 MyGeneration 通过实例化 GeneratedTemplate ,并调用Render方法开始生成过程。几乎大部分的模板开发工作都在Render方法里面完成。试试执行这个模板,你将会看到literal content goes here作为输出出现。
<%
public class GeneratedTemplate : DotNetScriptTemplate

{

public GeneratedTemplate(ZeusContext context) : base(context)
{}


public override void Render()

{
%>
Literal content goes here.
<%
}


}
%> 默认的UI接口代码: 在默认的模板的接口代码中,同样需要一个名为GeneratedGui的,继承DotNetScriptGui的强制类。如同模板主体代码的Render方法一样, MyGeneration 将调用Setup方法开始显示用户接口并收集输入。
public class GeneratedGui : DotNetScriptGui

{

public GeneratedGui(ZeusContext context) : base(context)
{}


public override void Setup()

{
}
}

获取输入:用户接口的代码块 在这个例子中,用户将通过接口选择一个表。这个是接口代码块的擅长的工作。用户接口获取的输入数据,将在模板主体代码中用来生成代码。
使用MyGeneration的接口代码:
public class GeneratedGui : DotNetScriptGui

{

public GeneratedGui(ZeusContext context) : base(context)
{}


public override void Setup()

{
ui.Title = ".NetScript C# Sample: Java Class";
ui.Width = 340;
ui.Height = 200;


// Setup Database selection combobox.
GuiLabel label_d = ui.AddLabel("lblDatabases", "Select a database:", "Select a database in the dropdown below.");
GuiComboBox cmbDatabases = ui.AddComboBox("databaseName", "Select a database.");


// Setup Tables selection multi-select listbox.
GuiLabel label_t = ui.AddLabel("lblTables", "Select table:", "Select table from the combobox below.");
GuiComboBox cmbTables = ui.AddComboBox("tableName", "Select a table.");


// bind data to the controls
cmbDatabases.BindData(MyMeta.Databases);
cmbDatabases.SelectedValue = MyMeta.DefaultDatabase.Name;
cmbTables.BindData( MyMeta.Databases[cmbDatabases.SelectedValue].Tables );

// Attach the onchange event to the cmbDatabases control.
cmbDatabases.AttachEvent("onchange", "cmbDatabases_onchange");

ui.ShowGui = true;
}


public void cmbDatabases_onchange(GuiComboBox control)

{
GuiComboBox cmbDatabases = ui["databaseName"] as GuiComboBox;
GuiComboBox cmbTables = ui["tableName"] as GuiComboBox;


cmbTables.BindData( MyMeta.Databases[cmbDatabases.SelectedValue].Tables );
}
} 使用.NET Windows Form API的接口代码:
下面的代码是不使用 MyGeneration API的替换方案,它可以达到与上面的代码同样的目的。
<%#REFERENCE System.Windows.Forms.dll %>
<%#NAMESPACE System.Windows.Forms %>
public class GeneratedGui : DotNetScriptGui

{

public GeneratedGui(ZeusContext context) : base(context)
{}


public override void Setup()

{
AcquireInputForm form = new AcquireInputForm(MyMeta, input);


if (form.ShowDialog() != DialogResult.OK)

{
ui.IsCanceled = true;
}
}
}


public class AcquireInputForm : Form

{
private ComboBox cboDatabases = new ComboBox();
private ComboBox cboTables = new ComboBox();
private Button btnOk = new Button();
private dbRoot meta;
private IZeusInput input;


public AcquireInputForm(dbRoot mymeta, IZeusInput zin)

{
this.meta = mymeta;
this.input = zin;


this.BindComboBox(cboDatabases, meta.Databases);
cboDatabases.SelectedItem = meta.DefaultDatabase.Name;
cboDatabases.Top = 10; cboDatabases.Left = 10; cboDatabases.Width = 200;
cboDatabases.SelectedIndexChanged += new EventHandler(cboDatabases_SelectedIndexChanged);


this.BindComboBox(cboTables, meta.DefaultDatabase.Tables);
cboTables.Top = 50; cboTables.Left = 10; cboTables.Width = 200;


btnOk.Text = "Ok";
btnOk.Top = 100; btnOk.Left = 10; btnOk.Width = 200;
btnOk.Click += new EventHandler(btnOk_Click);



this.Controls.AddRange( new Control[]
{cboDatabases, cboTables, btnOk} );
this.Text = ".NetScript C# Sample: Java Class";
this.Width = 230;
this.Height = 160;
}


public void cboDatabases_SelectedIndexChanged(object sender, EventArgs args)

{
this.BindComboBox(
cboTables,
meta.Databases[ cboDatabases.SelectedItem.ToString() ].Tables
);
}


public void btnOk_Click(object sender, EventArgs args)

{
if ((cboDatabases.SelectedIndex >= 0) &&
(cboTables.SelectedIndex >= 0))

{
input["databaseName"] = cboDatabases.SelectedItem.ToString();
input["tableName"] = cboTables.SelectedItem.ToString();
this.DialogResult = DialogResult.OK;
this.Close();
}
else

{
MessageBox.Show("Fill out the required fields.. PLEASE??");
}
}


private void BindComboBox(ComboBox cbo, IEnumerable myMetaCollection)

{
cbo.Items.Clear();
foreach (INameValueItem item in myMetaCollection)

{
cbo.Items.Add(item.ItemValue);
}
}
}

模板主体 模板主体是生成代码的主要执行地。下面讲解了我如何生成代码的步骤。
1、将期望输出的代码放入到Render的方法中如下的代码,你将看到我将要生成的类。这几乎都是当我要生成一个模板是必做的第一件事情。
<%
public class GeneratedTemplate : DotNetScriptTemplate

{

public GeneratedTemplate(ZeusContext context) : base(context)
{}


public override void Render()

{
string databaseName = input["databaseName"].ToString();
string tableName = input["tableName"].ToString();
%>

/**//*
* Employee.java
*
* Created on September 23, 2002, 12:59 PM
*/


package com.mygeneration.sample;


import java.sql.*;


import com.mygeneration.businessobjects.*;
import com.mygeneration.dataaccess.*;


public class Employee extends BizObj

{
public Employee()

{
}


// EmployeeID
public String getEmployeeID()

{
return getString(EmployeeSchema.EmployeeID.getFieldName());
}


public void setEmployeeID(String employeeID)

{
setString(EmployeeSchema.EmployeeID.getFieldName(), employeeID);
}
}<%
}


}
%>

2、添加动态代码把动态的代码添加到模板中,替换掉类名、属性名称以及数据类型。
<%
public class GeneratedTemplate : DotNetScriptTemplate

{

public GeneratedTemplate(ZeusContext context) : base(context)
{}


public override void Render()

{
string databaseName = input["databaseName"].ToString();
string tableName = input["tableName"].ToString();


IDatabase database = MyMeta.Databases[databaseName];
ITable table = database.Tables[tableName];

%>/**//*
* <%= table.Alias %>.java
*
* Created on <%= DateTime.Now.ToString() %>
*/


package com.mygeneration.sample;


import java.sql.*;


import com.mygeneration.businessobjects.*;
import com.mygeneration.dataaccess.*;


public class <%= table.Alias %> extends BizObj

{
public <%= table.Alias %>()

{
}
<%
foreach (IColumn column in table.Columns)

{
string datatype = this.GetJavaType(column);
%>
// <%= column.Alias %>
public <%= datatype %> get<%= column.Alias %>()

{
return get<%= datatype %>(<%= table.Alias %>Schema.<%= column.Alias %>.getFieldName());
}


public void set<%= column.Alias %>(<%= datatype %> m_<%= column.Alias %>)

{
set<%= datatype %>(<%= table.Alias %>Schema.<%= column.Alias %>.getFieldName(), m_<%= column.Alias %>);
}
<%
}
%>
}<%
}


private string GetJavaType(IColumn column)

{
string sqlServerType = column.DataTypeName;
int charLength = column.CharacterMaxLength;


switch (sqlServerType)

{
case "bit":
return "Boolean";
case "decimal":
case "float":
case "numeric":
case "money":
case "smallmoney":
case "real":
return "Decimal";
case "tinyint":
case "smallint":
case "int":
case "bigint":
return "Integer";
case "smalldatetime":
case "datetime":
return "Timestamp";
case "varchar":
case "char":
case "nvarchar":
case "nchar":
case "text":
if (charLength == 1)
return "Character";
else
return "String";
default:
return "Object";
}
}
}
%>

总结 使用 DotNetScript ,你将会把 MyGeneration 的模板开发提升到一个新的水平,提供更强大的功能以及能开发更复杂的系统。