标签:
之前做了一个项目,由于数据库表比较多,每次都手写model,还有数据库操作之类的东西,感觉浪费时间,也没技术含量,还容易出错,最主要的原因还是懒,不想翻来覆去的写这种代码,于是想到要用代码生成器直接生成,在网上找到很多,但是生成的代码要么看着不安逸,毕竟每个人的风格不同,要么就是生成很多自己根本不需要的垃圾代码,正好最近闲来无事,决定自己动手写一个。
一开始我是想到使用stringbuilder拼接字符串来实现,但是字符串拼接起来相当麻烦,代码量也很多,看起乱糟糟的很不舒服,还有就是得注意格式,不然生成出来的代码一团乱,于是看到园子里有大神用模板引擎实现过,但是看不到源码,用一段时间了还要付费,但是也提供了我一种思路,模板引擎可以实现。搜了很多关于模板引擎的资料,但是大多都是11年以前的,由于本人13年才正式踏入程序员行列,对于这项技术是不是过时了,我也不是很清楚,估计有了razor视图引擎,Nvelocity就显得有点不足了。这有篇介绍razor视图引擎做模板的例子:http://www.cnblogs.com/lxfqlcz/archive/2012/02/22/2363504.html,不过可以肯定的是,使用它比拼接字符串有很多好处,比如:开发效率高;代码不混乱,至少自己看着满意;不用注意格式,比如需要几个空格之类的;但是也有缺点,比如关键字不高亮;没有智能提示;也没法格式化,手动格式话了之后生成的代码就不是自己想要的格式了。所以一旦模板中有点小错误,很难找出来。
一、模板引擎之Nvelocity简介
网上关于这项技术的资料很多,下面罗列一些,就不介绍了。
http://www.cnblogs.com/hxling/archive/2011/10/23/2221918.html
http://www.cnblogs.com/cnfblog/archive/2010/10/18/1853987.html
http://www.cnblogs.com/waynechan/p/3489136.html
二、代码生成器的前期工作
1.查询表结构
1.1 方式1
SELECT col.name AS 列名 , typ.name AS 数据类型 , col.max_length AS 占用字节数 , col.is_nullable AS 是否允许非空 , col.is_identity AS 是否自增 , CASE WHEN EXISTS ( SELECT 1 FROM sys.indexes idx JOIN sys.index_columns idxCol ON ( idx.object_id = idxCol.object_id ) WHERE idx.object_id = col.object_id AND idxCol.index_column_id = col.column_id AND idx.is_primary_key = 1 ) THEN 1 ELSE 0 END AS 是否是主键 FROM sys.columns col LEFT JOIN sys.types typ ON ( col.system_type_id = typ.system_type_id AND col.user_type_id = typ.user_type_id ) WHERE col.object_id = ( SELECT object_id FROM sys.tables WHERE name = ‘SYS_ParameterGroup‘ ) 效果: GroupID int 4 0 1 1 GroupName varchar 200 1 0 0
1.2 方式2
SELECT a.colorder 字段序号 , a.name 字段名 , ( CASE WHEN COLUMNPROPERTY(a.id, a.name, ‘IsIdentity‘) = 1 THEN ‘1‘ ELSE ‘0‘ END ) 标识 , ( CASE WHEN ( SELECT COUNT(*) FROM sysobjects WHERE ( name IN ( SELECT name FROM sysindexes WHERE ( id = a.id ) AND ( indid IN ( SELECT indid FROM sysindexkeys WHERE ( id = a.id ) AND ( colid IN ( SELECT colid FROM syscolumns WHERE ( id = a.id ) AND ( name = a.name ) ) ) ) ) ) ) AND ( xtype = ‘PK‘ ) ) > 0 THEN ‘1‘ ELSE ‘0‘ END ) 主键 , b.name 类型 , a.length 占用字节数 , COLUMNPROPERTY(a.id, a.name, ‘PRECISION‘) AS 长度 , ISNULL(COLUMNPROPERTY(a.id, a.name, ‘Scale‘), 0) AS 小数位数 , ( CASE WHEN a.isnullable = 1 THEN ‘1‘ ELSE ‘0‘ END ) 允许空 , ISNULL(g.[value], ‘ ‘) AS 说明 FROM syscolumns a LEFT JOIN systypes b ON a.xtype = b.xusertype INNER JOIN sysobjects d ON a.id = d.id AND d.xtype = ‘U‘ AND d.name <> ‘dtproperties‘ LEFT JOIN syscomments e ON a.cdefault = e.id LEFT JOIN sys.extended_properties g ON a.id = g.major_id AND a.colid = g.minor_id LEFT JOIN sys.extended_properties f ON d.id = f.class AND f.minor_id = 0 WHERE b.name IS NOT NULL AND d.NAME = ‘USER_User‘ORDER BY a.id , a.colorder
效果:
目前还没搞明白sys.columns与syscolumns之间的区别,反正两者都能实现。查了MSDN貌似说的两者都差不多。
三、写一个Nvelocity帮助类,以方便我们使用Nvelocity,同时减少代码量,这里引用的Nvelocity当然需要先下载准备好,然后添加引用
1 using System; 2 using System; 3 using System.Web; 4 using System.IO; 5 using NVelocity; 6 using NVelocity.App; 7 using NVelocity.Context; 8 using NVelocity.Runtime; 9 using Commons.Collections; 10 using System.Windows.Forms; 11 12 13 namespace NVelocityDemo 14 { 15 /// <summary> 16 /// NVelocity模板工具类 NVelocityHelper 17 /// </summary> 18 public class NVelocityHelper 19 { 20 private VelocityEngine velocity = null; 21 private IContext context = null; 22 private string templateDir = "/Template"; 23 24 /// <summary> 25 /// 构造函数 26 /// </summary> 27 /// <param name="ps_TemplateDir">模板文件夹路径</param> 28 public NVelocityHelper(string ps_TemplateDir) 29 { 30 templateDir = ps_TemplateDir; 31 Init(); 32 } 33 34 /// <summary> 35 /// 无参数构造函数 36 /// </summary> 37 public NVelocityHelper() { Init(); } 38 39 /// <summary> 40 /// 初始化NVelocity模块 41 /// create by liubiqu@hotmail.com 2010-04-14 42 /// </summary> 43 private void Init() 44 { 45 //创建VelocityEngine实例对象 46 velocity = new VelocityEngine(); 47 48 //使用设置初始化VelocityEngine 49 ExtendedProperties props = new ExtendedProperties(); 50 props.AddProperty(RuntimeConstants.RESOURCE_LOADER, "file"); 51 props.AddProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, Application.StartupPath + templateDir); 52 props.AddProperty(RuntimeConstants.INPUT_ENCODING, "utf-8"); 53 props.AddProperty(RuntimeConstants.OUTPUT_ENCODING, "utf-8"); 54 velocity.Init(props); 55 56 //为模板变量赋值 57 context = new VelocityContext(); 58 } 59 60 /// <summary> 61 /// 给模板变量赋值 62 /// </summary> 63 /// <param name="key">模板变量</param> 64 /// <param name="value">模板变量值</param> 65 public void Add(string key, object value) 66 { 67 if (context == null) 68 context = new VelocityContext(); 69 context.Put(key, value); 70 } 71 72 /// <summary> 73 /// 通过获得模板文件生成结果字符串 74 /// </summary> 75 /// <param name="ps_TemplateFileName">模板文件名,为从模板目录开始的完整路径。即相对路径。如cms/news_view.htm</param> 76 public string GetStringFromVm(string ps_TemplateFileName) 77 { 78 //从文件中读取模板 79 Template template = velocity.GetTemplate(ps_TemplateFileName); 80 //合并模板 81 StringWriter writer = new StringWriter(); 82 template.Merge(context, writer); 83 //输出 84 string retValue = writer.GetStringBuilder().ToString(); 85 writer.Flush(); 86 writer.Close(); 87 writer.Dispose(); 88 return retValue; 89 } 90 91 /// <summary> 92 /// 生成字符串内容 93 /// </summary> 94 /// <param name="stringExpression">要解析的字符串数据</param> 95 /// <param name="logTag">Log标识</param> 96 /// <returns></returns> 97 public string GetStringFromSource(string ps_SourceStr) 98 { 99 StringWriter writer = new StringWriter(); 100 velocity.Evaluate(context, writer, "log", ps_SourceStr); 101 //输出 102 string retValue = writer.GetStringBuilder().ToString(); 103 writer.Flush(); 104 writer.Close(); 105 writer.Dispose(); 106 return retValue; 107 } 108 109 } 110 111 }
四、编写模板,这里来个简单的,生成实体类的模板,模板的后缀名为vm,必须设置文件的"复制到输出目录"属性,不然运行时会提示找不到模板文件。
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace $namespaceName { [Serializable] public class $tableName {
##自动属性方式 #if($isAutoProperty) #foreach($TableInfo in $listTableStructInfo) /// <summary> /// $TableInfo.Description /// </summary> public ${commonObj.GetType($TableInfo.Type)} ${commonObj.GetFirstUpperOrLower($TableInfo.Row,true)}{ get; set; } #end #else #foreach($TableInfo in $listTableStructInfo) private ${commonObj.GetType($TableInfo.Type)} _${commonObj.GetFirstUpperOrLower($TableInfo.Row,false)}; /// <summary> /// $TableInfo.Description /// </summary> public ${commonObj.GetType($TableInfo.Type)} ${commonObj.GetFirstUpperOrLower($TableInfo.Row,true)} { get { return _${commonObj.GetFirstUpperOrLower($TableInfo.Row,false)}; } set { _${commonObj.GetFirstUpperOrLower($TableInfo.Row,false)} = value; } } #end #end } }
五、调用模板生成文件
1 private void GetModel(ProgressBar bar, NVelocityHelper velocity, Common common) 2 { 3 int i = 0; bar.Maximum = lsTable.Count; 4 foreach (string table in lsTable) 5 { 6 //表结构 7 List<TableInfo> listTableStructInfo = Common.GetTableStruct(table); 8 if (listTableStructInfo.Count <= 0) 9 { 10 continue; 11 } 12 bar.Value = ++i; 13 //创建文件 14 string newPath = Common.CreateFile(Common.CreateFolder(rootPath, nameSpaceModel.NamespaceEntity), common.GetFirstUpperOrLower(table, true) + ".cs"); 15 //命名空间名称 16 velocity.Add("namespaceName", nameSpaceModel.NamespaceEntity); 17 //表名 18 velocity.Add("tableName", table); 19 //表结构 20 velocity.Add("listTableStructInfo", listTableStructInfo); 21 //调用方法需要的对象 22 velocity.Add("commonObj", common); 23 //生成自动属性 24 if (nameSpaceModel.IsAutoProperty) 25 { 26 velocity.Add("isAutoProperty", true); 27 } 28 string text = velocity.GetStringFromVm("model.vm"); 29 File.AppendAllText(newPath, text); 30 } 31 bar.Value = 0; 32 }
生成实体类的效果如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Models { [Serializable] public class USER_User { /// <summary> /// 用户ID /// </summary> public string UserID{ get; set; } /// <summary> /// 用户名 /// </summary> public string Name{ get; set; } /// <summary> /// 证件类型ID,对应SYS_CardType表 /// </summary> public int CardTypeID{ get; set; } /// <summary> /// 证件号码 /// </summary> public string CardNum{ get; set; } } }
完整代码下载地址:demo下载
标签:
原文地址:http://www.cnblogs.com/ginb/p/5044528.html