背景
编写代码生成器的目的是为了进一步减少程序员的重复性“体力劳动”,让程序员有更多的时间去做创造性的工作,提高编码的质量。我在编码和架构过程中层自己开发了一系列代码生成工具,本着开源和分享的目的,会在本期和后期博客中倾情奉献给有需要的朋友,不足指出也请多包含,因为共享源码,你也可以进行修改使用。
实现思路
预先编制模版,包括实体类、数据访问类、业务逻辑类、配置文件,基于已定义的数据库结构进行模版替换生成。
关键模版代码
1、实体类模版(EntityClassTemplate.txt)
/************************************************************************************
* ${CopyRight}
* File:
* ${EntityClassName}.cs
* Description:
*
* Author:
* ${Author}
* ${AuthorEmail}
* ${Online}
* Finish DateTime:
* ${Date}
* History:
***********************************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
namespace ${EntityNameSpace}
{
/// <summary>
/// 实体类${EntityClassName}
/// </summary>
[Serializable]
public class ${EntityClassName}
{
#region 私有字段
${PrivateFields}
#endregion
#region 公有属性
${PublicAttribute}
#endregion
}
}
2、实体类映射文件模版(EntityMapperHandler.txt)
/************************************************************************************
* ${CopyRight}
* File:
* EntityMapperHandler.cs
* Description:
* 实体类映射文件解析类
* Author:
* ${Author}
* ${AuthorEmail}
* ${Online}
* Finish DateTime:
* ${Date}
* History:
*
***********************************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.IO;
using System.Configuration;
using System.Reflection;
namespace ${TopComponentsNameSpace}
{
using ${ComponentNameSpace};
/// <summary>
/// 实体类映射文件解析类,使用单例设计模式实现
/// </summary>
public class EntityMapperHandler
{
#region 私有字段
private static EntityMapperHandler instance;
private static Dictionary<string, XmlClassMap> mapperDictionary=new Dictionary<string,XmlClassMap>();
#endregion
#region 构造方法
private EntityMapperHandler() { }
private EntityMapperHandler(string mapperFiles)
{
lock (this)
{
string[] files = mapperFiles.Split(new char[] { ',' });
foreach (string file in files)
{
Stream s = null;
if (file.StartsWith("assembly://"))
{
string prefixStr = "assembly://";
string assemblyName = file.Substring(prefixStr.Length, file.LastIndexOf("/") - prefixStr.Length);
string fileName = file.Substring(file.LastIndexOf("/") + 1);
s = Assembly.Load(assemblyName).GetManifestResourceStream(fileName);
}
else
{
s = new FileStream(file, FileMode.Open);
}
this.CreateMapperDictionary(s);
}
}
}
private EntityMapperHandler(Stream mapperStream)
{
lock (this)
{
this.CreateMapperDictionary(mapperStream);
}
}
#endregion
#region 创建映射字典
/// <summary>
/// 解析实体关系映射文件,把解析的结果保存到字典集合中
/// </summary>
/// <param name="mapperStream">实体关系映射文件流</param>
private void CreateMapperDictionary(Stream mapperStream)
{
XmlDocument doc = new XmlDocument();
doc.Load(mapperStream);
//解析实体类与表的映射
XmlNodeList nl = doc.GetElementsByTagName("class");
foreach (XmlNode node in nl)
{
string className = node.Attributes["name"].Value;
string tableName = node.Attributes["table"].Value;
//解析属性与字段的映射
XmlClassMap classMap = new XmlClassMap(className, tableName);
XmlNodeList childNl = node.ChildNodes;
foreach (XmlNode childNode in childNl)
{
if (childNode.Name == "property")
{
#region 解析属性
string propertyName = childNode.Attributes["name"].Value;
string columnName = childNode.Attributes["column"].Value;
XmlPropertyMap propertyMap = new XmlPropertyMap(propertyName, columnName);
classMap.Properties.Add(propertyName, propertyMap);
#endregion
#region 解析自增列
XmlAttribute attrIdentity = childNode.Attributes["isIdentity"];
if (attrIdentity != null && attrIdentity.Value == "true")
{
classMap.Identity = propertyMap;
}
#endregion
#region 解析主键
XmlAttribute attrPK = childNode.Attributes["isPK"];
if (attrPK != null && attrPK.Value == "true")
{
classMap.Ids.Add(propertyName, propertyMap);
}
#endregion
}
}
mapperDictionary.Add(className, classMap);
}
mapperStream.Close();
mapperStream.Dispose();
}
#endregion
#region 获取解析器实例
/// <summary>
/// 获取本类实例的静态方法
/// </summary>
/// <param name="mapperFile">映射文件路径</param>
/// <returns>返回本类实例</returns>
public static EntityMapperHandler GetInstance(string mapperFile)
{
if (instance == null)
{
instance = new EntityMapperHandler(mapperFile);
}
return instance;
}
/// <summary>
/// 获取本类实例的静态方法
/// </summary>
/// <param name="mapperStream">映射文件流</param>
/// <returns>返回本类实例</returns>
public static EntityMapperHandler GetInstance(Stream mapperStream)
{
if (instance == null)
{
instance = new EntityMapperHandler(mapperStream);
}
return instance;
}
/// <summary>
/// 获取本类实例的静态方法,默认读取appSetting中entityMapperFile对应的文件,可以配置多个以逗号分隔
/// </summary>
/// <returns>返回本类实例</returns>
public static EntityMapperHandler GetInstance()
{
if (instance == null)
{
string mapperFiles = ConfigurationManager.AppSettings["entityMapperFile"];
instance = new EntityMapperHandler(mapperFiles);
}
return instance;
}
#endregion
/// <summary>
/// 获取映射字典
/// </summary>
/// <returns></returns>
public Dictionary<string, XmlClassMap> GetMapDictionary()
{
return mapperDictionary;
}
/// <summary>
/// 根据实体类型获取对应的表名
/// </summary>
/// <param name="type">实体类型</param>
/// <returns>返回对应的表名称</returns>
public string GetTableNameByClassType(Type type)
{
return mapperDictionary[type.Name].TableName;
}
}
}
3、数据访问接口模版(IDAOTemplate.txt)
using System;
using System.Collections.Generic;
using System.Text;
namespace ${DAONameSpace}.Interface
{
using ${EntityNameSpace};
public interface I${EntityClassName}${DAOClassPostFix} : IBase${DAOClassPostFix}<${EntityClassName}>
{
}
}
4、数据访问类模版(DAOTemplate.txt)
using System;
using System.Collections.Generic;
using System.Text;
namespace ${DAONameSpace}.Implements
{
using ${EntityNameSpace};
using ${DAONameSpace}.Interface;
public class ${EntityClassName}${DAOClassPostFix} : Base${DAOClassPostFix}<${EntityClassName}>, I${EntityClassName}${DAOClassPostFix}
{
}
}
5、业务逻辑接口模版(IBIZTemplate.txt)
using System;
using System.Collections.Generic;
using System.Text;
namespace ${BIZNameSpace}.Interface
{
using ${EntityNameSpace};
public interface I${EntityClassName}${BIZClassPostFix} : IBase${BIZClassPostFix}<${EntityClassName}>
{
}
}
6、业务逻辑类模版(BIZTemplate.txt)
using System;
using System.Collections.Generic;
using System.Text;
namespace ${BIZNameSpace}.Implements
{
using ${EntityNameSpace};
using ${BIZNameSpace}.Interface;
using ${DAONameSpace}.Interface;
public class ${EntityClassName}${BIZClassPostFix} : Base${BIZClassPostFix}<${EntityClassName}>, I${EntityClassName}${BIZClassPostFix}
{
#region 属性注入
private I${EntityClassName}${DAOClassPostFix} ${CamelDAOClassPostFix};
public I${EntityClassName}${DAOClassPostFix} ${DAOClassPostFix}
{
set { this.${CamelDAOClassPostFix} = value; base.Base${DAOClassPostFix} = this.${CamelDAOClassPostFix}; }
}
#endregion
}
}
使用教程
1、 打开VS,新建一个空白解决方案MesnacDemo。
2、 右键点击空白解决方案,添加一个新的类库项目Mesnac,如下图所示:
3、 启动数据库服务器并运行代码生成器,设置好,服务器、用户名、密码,选择数据库,点击“测试连接”按钮,出现测试成功提示,点击测试连接成功消息框的“确定按钮”后“下一步”变为可用,如下图所示:
4、 点击“下一步”按钮,出现参数设置窗口,如下图:
5、设置相应的参数信息,在“输出目录”项填解决方案MesnacDemo.sln所在的目录,你可以点击“保存设置”按钮进行当前设计的保存。然后点击“代码生成”按钮,会出现生成文件个数的消息框,如下图:
6、 在VS的解决方案小窗口的工具栏上点击“显示所有文件”按钮,如下图:
7、选中Business、Components、Data、Entity、applicationContext.xml、EntityMapperHandler.cs、SpringObjectFactory.cs点鼠标右键,在弹出菜单中选择“包括在项目中”菜单项,结果如下图:
8、选中Entity文件夹中的EntityMapper.xml,在属性窗口中把“生成操作”设置为“嵌入的资源”。
9、右键点击Mesnac类库项目,在弹出菜单中选择“添加引用”菜单项,分别添加System.Web、System.Configuration、Common.Logging.dll、Spring.Core.dll 、Spring.Aop.dll、Spring.Data.dll。然后编译此类库项目,看是否编译通过。
10、 在解决方案中添加一个ASP.NET网站,并把Mesnac类库中的applicationContext.xml剪贴到网站根目录下,然后再网站中添加Web.config文件,如下图所示:
11、修改Web.config,实现ASP.NET与Spring.NET的整合。代码如下:
<?xml version="1.0"?>
<configuration>
<configSections>
<sectionGroup name="spring">
<section name="context"
type="Spring.Context.Support.WebContextHandler, Spring.Web"/>
<section name="objects"
type="Spring.Context.Support.DefaultSectionHandler, Spring.Core"/>
<section name="parsers"
type="Spring.Context.Support.NamespaceParsersSectionHandler, Spring.Core"/>
</sectionGroup>
</configSections>
<spring>
<context type="Spring.Context.Support.WebApplicationContext, Spring.Web">
<resource uri="~/applicationContext.xml"/>
</context>
<parsers>
<parser type="Spring.Aop.Config.AopNamespaceParser, Spring.Aop"/>
</parsers>
</spring>
<appSettings>
<!--实体映射文件的位置-->
<add key="entityMapperFile"
value="assembly://Mesnac/Mesnac.Entity.EntityMapper.xml"/>
</appSettings>
<connectionStrings/>
<system.web>
<httpHandlers>
<!--Spring Web 支持-->
<add verb="*" path="*.aspx"
type="Spring.Web.Support.PageHandlerFactory, Spring.Web"/>
</httpHandlers>
<httpModules>
<!--Spring Web 支持-->
<add name="Spring"
type="Spring.Context.Support.WebSupportModule, Spring.Web"/>
</httpModules>
<compilation debug="false">
<assemblies>
<add assembly="System.Transactions, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=B77A5C561934E089"/>
</assemblies>
</compilation>
<authentication mode="Windows"/>
</system.web>
</configuration>
12、右键点击网站项目,在弹出菜单中选择“添加引用”,添加对Spring.Web.dll、Spring.Web.Extensions.dll和Mesnac类库项目的引用。
13、在Default.aspx页面上放置一个GridView控件,在对应的代码隐藏文件Default.aspx.cs文件中添加相应代码如下所示:
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using Mesnac.Business.Interface;
public partial class _Default : System.Web.UI.Page
{
#region 属性注入
private ISys_ModuleManager sys_ModuleManager;
public ISys_ModuleManager Sys_ModuleManager
{
set { sys_ModuleManager = value; }
}
#endregion
protected void Page_Load(object sender, EventArgs e)
{
//数据绑定操作
if (!this.IsPostBack)
{
this.GridView1.DataSource = this.sys_ModuleManager.GetAllList();
this.GridView1.DataBind();
}
}
}
14、修改applicationContext.xml,在文件后天添加如下代码:
<!--page config-->
<object type="Default.aspx">
<property name="Sys_ModuleManager" ref="sys_ModuleManager" />
</object>
15、把站点设置为启动项目、把Default.aspx设置为启动页,按Ctrol+F5运行,如下图: