代码自动生成工具MyGeneration之一
前段时间用C#做网站,用到了大量数据库相关的东西。网站采用3层结构,即数据访问层(Data Access Layer),业务逻辑层(Business Logic Layer),页面表现层().做了一段时间,发现向数据访问层和业务逻辑层加入新的类,数据库的表结构改了,还要对应的修改数据访问层和业务逻辑层的代码,这个工作很是繁琐,无聊,而且容易出错。做了几次之后就想有什么办法可以让机器自动完成呢?
联想到以前看过Java似乎有个Hibernate,可以很方便的实现对象关系映射(ORM),即自动的从数据库的表生成对应的对象,.Net也应该有类似的功能吧。于是找啊找,发现了很多.Net的ORM工具,不过都有缺点,就是代码得依赖于那些ORM工具,我希望能够让机器按我的要求生成我自己的代码,这样就更加灵活了。
于是乎,发现了CodeSmith和MyGeneration,CodeSmith是 网上传的.NET 程序员十种必备工具之一,我们写代码时,经常需要重复完成某些特定的任务,例如编写数据访问代码或者生成自定义集合。我们可以用CodeSmith编写模板自动完成这些任务,从而不仅提高工作效率,而且能够自动完成那些最为乏味的任务。可惜,CodeSmith是需要注册的,试用版只能用15天。而MyGeneration基本上和CodeSmith的功能差不多哦,但是他是开源的。我选软件的原则是能开源免费的就用,实在没替代了才选那些需要注册的,有版权的软件。所以就选MyGeneration了。
用过一段时间后感觉MyGeneration主要是为了自动生成数据库相关的代码的,可能C#用得比较多,其实我们可以用它生成任何代码,C++,JavaScript...而且还不仅仅局限于数据库,其他方面的代码也可以用MyGeneration自动生成。比如我们经常用数据访问层和业务逻辑层,用MyGeneration就可以自动生成这些代码,我们可以不用手动写代码了。比如数据访问层,我们需要调用一个存储过程,用MyGeneration我们只需要选择生成存储过程代码的模板,执行一下脚本,然后在界面上选择数据库上某个存储过程,然后就自动生成了数据库访问代码,整个过程只需要点几下鼠标,代码就自动生成了。这对于需要大量操作数据库的程序员来说,效率是多大的提升啊。
废话少说,还是来点实在的吧。首先声明,我的MyGeneration版本是:1.3.0.3
安装完MyGeneration后,第一次启动会要求进行一些数据库相关的配置。如图:
ConnectionString: 就是指定连接哪个数据库了,填好这个就可以点确定了。
下面来看一看其他的项都是什么。
Language Mapping:就是指定数据库和对象基本类型的映射关系。让我们打开Languages.xml文件看一下吧:
1 <Language From="SQL" To="C#"> 2 <Type From="bigint" To="long" /> 3 <Type From="binary" To="object" /> 4 <Type From="bit" To="bool" /> 5 <Type From="char" To="string" /> 6 <Type From="datetime" To="DateTime" /> 7 <Type From="decimal" To="decimal" /> 8 <Type From="float" To="double" /> 9 <Type From="image" To="byte[]" /> 10 <Type From="int" To="int" /> 11 <Type From="money" To="decimal" /> 12 <Type From="nchar" To="string" /> 13 <Type From="ntext" To="string" /> 14 <Type From="numeric" To="decimal" /> 15 <Type From="nvarchar" To="string" /> 16 <Type From="real" To="float" /> 17 <Type From="smalldatetime" To="DateTime" /> 18 <Type From="smallint" To="short" /> 19 <Type From="smallmoney" To="decimal" /> 20 <Type From="text" To="string" /> 21 <Type From="timestamp" To="byte[]" /> 22 <Type From="tinyint" To="byte" /> 23 <Type From="uniqueidentifier" To="Guid" /> 24 <Type From="varbinary" To="byte[]" /> 25 <Type From="varchar" To="string" /> 26 <Type From="xml" To="string" /> 27 <Type From="sql_variant" To="object" /> 28 </Language>
这是里面的一段内容,很明显,是数据库SQL的字段转到C#是什么类型,里面没有C++的,假如我们要让它支持C++的话,需要在这里加入SQL到C++的类型转换。
Database Target Mapping:先看里面的内容吧:
1 <DbTarget From="ACCESS" To="DAO"> 2 <Type From="Text" To="DAO.dbText" /> 3 <Type From="Memo" To="DAO.dbMemo" /> 4 <Type From="DateTime" To="DAO.dbDate" /> 5 <Type From="Currency" To="DAO.dbCurrency" /> 6 <Type From="Yes/No" To="DAO.dbBoolean" /> 7 <Type From="OLE Object" To="DAO.dbLongBinary" /> 8 <Type From="Hyperlink" To="DAO.dbMemo" /> 9 <Type From="Double" To="DAO.dbDouble" /> 10 <Type From="Replication ID" To="DAO.dbGUID" /> 11 <Type From="Long" To="DAO.dbLong" /> 12 <Type From="Single" To="DAO.dbSingle" /> 13 <Type From="Decimal" To="DAO.dbDecimal" /> 14 <Type From="Byte" To="DAO.dbByte" /> 15 <Type From="Integer" To="DAO.dbInteger" /> 16 </DbTarget>
呵呵,一目了然,就是Access数据库用DAO的方式访问,数据库的列的类型对应的DAO里是什么类型。
UseMetaData目前没什么用。
看看MyGeneration的界面吧:
先让我们体验一下吧。
展开Template Browser面板下"d00dads - C#", 双击 “d00dads - Invoke a Stored Procedure", 让工作区显示其内容,
然后点击工具栏上的 "Execute" 按钮,如图红框所示:
弹出对话框,如图:
选择数据库,存储过程,存储过程类型,点确定(OK)。
然后可以看到工作区 Output 里输出了代码了。例如:
1 using System.Data; 2 using System.Collections.Specialized; 3 using System.Data.SqlClient; 4 5 6 7 public virtual void dm_exec_cursors (int spid) 8 { 9 ListDictionary parameters = new ListDictionary(); 10 11 parameters.Add( new SqlParameter("@spid", SqlDbType.Int, 0), spid); 12 LoadFromSqlNoExec("dm_exec_cursors", parameters); 13 }
这就是MyGeneration自动获取了存储过程的输入参数,然后在代码里构造相应的参数,然后生成的代码。
这只是MyGeneration自带的模板生成的,大家可以试一试其他的模板的效果。
里面有自动根据表结构生成BLL的类......看下效果:
1 /* 2 '=============================================================================== 3 ' Generated From - CSharp_dOOdads_BusinessEntity.vbgen 4 ' 5 ' ** IMPORTANT ** 6 ' How to Generate your stored procedures: 7 ' 8 ' SQL = SQL_StoredProcs.vbgen 9 ' ACCESS = Access_StoredProcs.vbgen 10 ' ORACLE = Oracle_StoredProcs.vbgen 11 ' FIREBIRD = FirebirdStoredProcs.vbgen 12 ' POSTGRESQL = PostgreSQL_StoredProcs.vbgen 13 ' 14 ' The supporting base class OleDbEntity is in the Architecture directory in "dOOdads". 15 ' 16 ' This object is 'abstract' which means you need to inherit from it to be able 17 ' to instantiate it. This is very easilly done. You can override properties and 18 ' methods in your derived class, this allows you to regenerate this class at any 19 ' time and not worry about overwriting custom code. 20 ' 21 ' NEVER EDIT THIS FILE. 22 ' 23 ' public class YourObject : _YourObject 24 ' { 25 ' 26 ' } 27 ' 28 '=============================================================================== 29 */ 30 // Generated by MyGeneration Version # (1.3.0.3) 31 using System; 32 using System.Data; 33 using System.Data.OleDb; 34 using System.Collections; 35 using System.Collections.Specialized; 36 using MyGeneration.dOOdads; 37 namespace Your.Namespace 38 { 39 public abstract class _Users : OleDbEntity 40 { 41 public _Users() 42 { 43 this.QuerySource = "Users"; 44 this.MappingName = "Users"; 45 } 46 //================================================================= 47 // public Overrides void AddNew() 48 //================================================================= 49 // 50 //================================================================= 51 public override void AddNew() 52 { 53 base.AddNew(); 54 55 } 56 57 58 public override string GetAutoKeyColumn() 59 { 60 return "ID"; 61 } 62 public override void FlushData() 63 { 64 this._whereClause = null; 65 this._aggregateClause = null; 66 base.FlushData(); 67 } 68 69 //================================================================= 70 // public Function LoadAll() As Boolean 71 //================================================================= 72 // Loads all of the records in the database, and sets the currentRow to the first row 73 //================================================================= 74 public bool LoadAll() 75 { 76 ListDictionary parameters = null; 77 78 return base.LoadFromSql("[" + this.SchemaStoredProcedure + "proc_UsersLoadAll]", parameters); 79 } 80 81 //================================================================= 82 // public Overridable Function LoadByPrimaryKey() As Boolean 83 //================================================================= 84 // Loads a single row of via the primary key 85 //================================================================= 86 public virtual bool LoadByPrimaryKey() 87 { 88 ListDictionary parameters = new ListDictionary(); 89 90 return base.LoadFromSql("[" + this.SchemaStoredProcedure + "proc_UsersLoadByPrimaryKey]", parameters); 91 } 92 93 #region Parameters 94 protected class Parameters 95 { 96 97 public static OleDbParameter ID 98 { 99 get 100 { 101 return new OleDbParameter("@ID", OleDbType.Integer, 0); 102 } 103 } 104 105 public static OleDbParameter Alias 106 { 107 get 108 { 109 return new OleDbParameter("@Alias", OleDbType.VarChar, 2147483647); 110 } 111 } 112 113 } 114 #endregion 115 116 #region ColumnNames 117 public class ColumnNames 118 { 119 public const string ID = "ID"; 120 public const string Alias = "Alias"; 121 static public string ToPropertyName(string columnName) 122 { 123 if(ht == null) 124 { 125 ht = new Hashtable(); 126 127 ht[ID] = _Users.PropertyNames.ID; 128 ht[Alias] = _Users.PropertyNames.Alias; 129 } 130 return (string)ht[columnName]; 131 } 132 static private Hashtable ht = null; 133 } 134 #endregion 135 136 #region PropertyNames 137 public class PropertyNames 138 { 139 public const string ID = "ID"; 140 public const string Alias = "Alias"; 141 static public string ToColumnName(string propertyName) 142 { 143 if(ht == null) 144 { 145 ht = new Hashtable(); 146 147 ht[ID] = _Users.ColumnNames.ID; 148 ht[Alias] = _Users.ColumnNames.Alias; 149 } 150 return (string)ht[propertyName]; 151 } 152 static private Hashtable ht = null; 153 } 154 #endregion 155 #region StringPropertyNames 156 public class StringPropertyNames 157 { 158 public const string ID = "s_ID"; 159 public const string Alias = "s_Alias"; 160 } 161 #endregion 162 163 #region Properties 164 165 public virtual Integer ID 166 { 167 get 168 { 169 return base.GetInteger(ColumnNames.ID); 170 } 171 set 172 { 173 base.SetInteger(ColumnNames.ID, value); 174 } 175 } 176 public virtual String Alias 177 { 178 get 179 { 180 return base.GetString(ColumnNames.Alias); 181 } 182 set 183 { 184 base.SetString(ColumnNames.Alias, value); 185 } 186 } 187 #endregion 188 189 #region String Properties 190 191 public virtual string s_ID 192 { 193 get 194 { 195 return this.IsColumnNull(ColumnNames.ID) ? string.Empty : base.GetIntegerAsString(ColumnNames.ID); 196 } 197 set 198 { 199 if(string.Empty == value) 200 this.SetColumnNull(ColumnNames.ID); 201 else 202 this.ID = base.SetIntegerAsString(ColumnNames.ID, value); 203 } 204 } 205 public virtual string s_Alias 206 { 207 get 208 { 209 return this.IsColumnNull(ColumnNames.Alias) ? string.Empty : base.GetStringAsString(ColumnNames.Alias); 210 } 211 set 212 { 213 if(string.Empty == value) 214 this.SetColumnNull(ColumnNames.Alias); 215 else 216 this.Alias = base.SetStringAsString(ColumnNames.Alias, value); 217 } 218 } 219 #endregion 220 221 222 private AggregateClause _aggregateClause = null; 223 #endregion 224 225 protected override IDbCommand GetInsertCommand() 226 { 227 228 OleDbCommand cmd = new OleDbCommand(); 229 cmd.CommandType = CommandType.StoredProcedure; 230 cmd.CommandText = "[" + this.SchemaStoredProcedure + "proc_UsersInsert]"; 231 232 CreateParameters(cmd); 233 234 return cmd; 235 } 236 237 protected override IDbCommand GetUpdateCommand() 238 { 239 240 OleDbCommand cmd = new OleDbCommand(); 241 cmd.CommandType = CommandType.StoredProcedure; 242 cmd.CommandText = "[" + this.SchemaStoredProcedure + "proc_UsersUpdate]"; 243 244 CreateParameters(cmd); 245 246 return cmd; 247 } 248 249 protected override IDbCommand GetDeleteCommand() 250 { 251 252 OleDbCommand cmd = new OleDbCommand(); 253 cmd.CommandType = CommandType.StoredProcedure; 254 cmd.CommandText = "[" + this.SchemaStoredProcedure + "proc_UsersDelete]"; 255 256 OleDbParameter p; 257 258 return cmd; 259 } 260 261 private IDbCommand CreateParameters(OleDbCommand cmd) 262 { 263 OleDbParameter p; 264 265 p = cmd.Parameters.Add(Parameters.ID); 266 p.SourceColumn = ColumnNames.ID; 267 p.SourceVersion = DataRowVersion.Current; 268 p = cmd.Parameters.Add(Parameters.Alias); 269 p.SourceColumn = ColumnNames.Alias; 270 p.SourceVersion = DataRowVersion.Current; 271 return cmd; 272 } 273 } 274 }
这就是自动获得表结构,然后从字段映射成类里面的成员,并且还有一些插入,更新,删除的代码。
当然自带的模板生成的代码不一定符合我们的需要,但是我们可以根据需要自己写一些模板来生成符合自己需要的代码,这也是非常容易的事,欲知如何实现,请看下回文章。
本文转载自:http://blog.csdn.net/zxcred/article/details/2778193