个人觉得学习 codesmith 需要一点基础:
需要懂一点ASP.Net 会写三层架构 对程序员枯燥的生活有一定认识
而PetShop随着版本的不断更新,至现在基于.Net 2.0的PetShop4.0为止,整个设计逐渐变得成熟而优雅,有很多可以借鉴之处。为了简化文章 我们只会 Model , IDAL , SQLServerDAL , DALFactory , Bll ,Web 进行生成
研究petshop有一段时间啦 网上它关于的文章也不记其数
我们先了解一下petshop4.0:
petshop系统架构设计:http://www.cnblogs.com/wayfarer/archive/2007/03/23/375382.html
数据实体对应数据库中相应的数据表。它们没有行为,仅用于表现对象的数据。这些实体类都被放到Model程序集中,例如数据表Products对应的实体类ProductInfo,这些对象并不具有持久化的功能,简单地说,它们是作为数据的载体,便于业务逻辑针对相应数据表进行读/写操作。虽然这些类的属性分别映射了数据表的列,而每一个对象实例也恰恰对应于数据表的每一行,但这些实体类却并不具备对应的数据库访问能力。
让我们共同学习petshop 实体层 的生成
我们需要得到的是什么? 需要定义一个什么样的模板
首先例出你所想的目标程序(以ProductInfo为例) 找出目标程序的可变量
using System;
namespace PetShop.Model {
/**//// <summary>
/// Business entity used to model a product
/// </summary>
[Serializable]
public class ProductInfo {
// Internal member variables
private string id;
private string name;
private string description;
private string image;
private string categoryId;
/**//// <summary>
/// Default constructor
/// </summary>
public ProductInfo() { }
/**//// <summary>
/// Constructor with specified initial values
/// </summary>
/// <param name="id">Product Id</param>
/// <param name="name">Product Name</param>
/// <param name="description">Product Description</param>
/// <param name="image">Product image</param>
/// <param name="categoryId">Category Id</param>
public ProductInfo(string id, string name, string description, string image, string categoryId) {
this.id = id;
this.name = name;
this.description = description;
this.image = image;
this.categoryId = categoryId;
}
// Properties
public string Id {
get { return id; }
}
public string Name {
get { return name; }
}
public string Description {
get { return description; }
}
public string Image {
get { return image; }
}
public string CategoryId {
get { return categoryId; }
}
}
}
可以看出在不同项目中的不同 Model 会有不同命名空间,不同的类名,不同的字段 属性 方法
命名空间需要定义一个属性 而类 字段 属性 方法 需要从数据库中获得 需要定义一个数据库访问属性
这回,我们开始探讨CodeSmith与数据库的联系,在CodeSmith中自带一个程序集SchemaExplorer.dll,这个程序集中的类主要用于获取数据库中各种对象的结构。
因为是针对表去生成属性,则首先要定义一些变量,然后指明这些变量类型为数据库中的表,这样我们可以通过这个数据表类型的变量得到相应的表的信息。
<%@ Property Name="SourceTable" Type="SchemaExplorer.TableSchema" Category="Context" Description="Table that the stored procedures should be based on." %>
如果想访问视图的话,则将变量类型Type中的SchemaExplorer.TableSchema修改为SchemaExplorer.ViewSchema即可。
详细请见: CodesmithAPI help 中的 SchemaExplorer
模板代码: 写一个模板不是为了生成一个类(ProductInfo) 而是多个相似的类 我们可以通 Properties 设置对应的值 设置类对应的不同的数据库对象
Code
<%--
Name:
Author:
Description:
--%>
<%@ CodeTemplate Language="C#" TargetLanguage="C#" Debug="False" Description="Create a list of properties from database table." %>
<%@ Property Name="Namespace" Type="System.String" Default="" Optional="False" Category="String" Description="" OnChanged="" Editor="" EditorBase="" Serializer="" %>
<%@ Property Name="SourceTable" Type="SchemaExplorer.TableSchema" Category="Context" Description="Table that the object is based on." %>
<%@ Map Name="CSharpAlias" Src="System-CSharpAlias" Description="System to C# Type Map" %>
<%@ Assembly Name="SchemaExplorer" %>
<%@ Import Namespace="SchemaExplorer" %>
<%@ Import Namespace="System.Text" %>
using System;
namespace <% =Namespace %>.Model {
/**//// <summary>
/// Business entity used to model a <%= GetClassName(SourceTable) %>
/// </summary>
[Serializable]
public class <%= GetClassName(SourceTable) %> {
// Internal member variables
<% foreach (ColumnSchema column in this.SourceTable.Columns) {%>
private <%= CSharpAlias[column.SystemType.FullName] %> <%= StringUtil.ToCamelCase(column.Name) %>;
<%} %>
/**//// <summary>
/// Default constructor
/// </summary>
public <%= GetClassName(SourceTable) %>() { }
/**//// <summary>
/// Constructor with specified initial values
/// </summary>
<% foreach (ColumnSchema column in this.SourceTable.Columns) {%>
<% Response.Write("/// <param name=\"");%><%= StringUtil.ToCamelCase(column.Name) %><% Response.Write("\">");%><% =SourceTable.Name%> <%= StringUtil.ToCamelCase(column.Name) %> <% Response.Write("</param>");%>
<%} %>
public <%= GetClassName(SourceTable) %>(<%int i=0; foreach (ColumnSchema column in this.SourceTable.Columns) {%><% if(i!=0){Response.Write(",");} i++; %><%= CSharpAlias[column.SystemType.FullName] %> <%= StringUtil.ToCamelCase(column.Name) %><%} %>) {
<% foreach (ColumnSchema column in this.SourceTable.Columns) {%>
this.<%= StringUtil.ToCamelCase(column.Name) %>=<%= StringUtil.ToCamelCase(column.Name) %>;
<%} %>
}
// Properties
<% foreach (ColumnSchema column in this.SourceTable.Columns) {%>
public <%= CSharpAlias[column.SystemType.FullName] %> <%= StringUtil.ToPascalCase(column.Name) %> {
get { return <%= StringUtil.ToCamelCase(column.Name) %>}
}
<%} %>
}
}
<script runat="template">
public string GetClassName(TableSchema table)
{
if (table.Name.EndsWith("s"))
{
return table.Name.Substring(0, table.Name.Length - 1)+"Info";
}
else
{
if(table==null)
{
return null;
}
return table.Name + "Info";
}
}
</script>
哎。。。 奇怪 怎么引入了 MAP
因为我们需要把系统类型转为C#类型 我在模板中使用了<%= CSharpAlias[column.SystemType.FullName] %>
把鼠标指针移到 CSharpAlias 就可以看到它的上级 通过API去了解它的详细介绍和它上级的详细介绍
Author:Nadim
2008-8-23 13:37:28