对于C#面向对象的思想,我们习惯于将数据库中的表创建对应的数据模型;
但假如数据表很多时,我们手动增加模型类会显得很浪费时间;
这个时候有些人会用微软提供的EntityFrameWork,这个框架很强大,编写代码效率也很高,但很由于性能差,在复杂查询的时候生成的sql脚本效率不是很高,所以有的时候不会去使用它;
这个时候就会有CodeSmith来协助我们去完成那些费时费力的工作:
CodeSmith如何使用,网上也有很详细的介绍了,下面代码只是简单介绍
属性SourceDataBase是连接的数据库,CodeSmith提供连接数据库的方法很方便
属性NameSpace顾名思义就是命名空间
1 <%-- 2 Name:批量生成实体类 3 Author: TitanChen 4 Description:批量将数据库中的表结构生成数据模型 5 --%> 6 <%@ CodeTemplate Language="C#" TargetLanguage="C#" Description="Template description here." %> 7 <%@ Assembly Name="SchemaExplorer" %> 8 <%@ Import Namespace="SchemaExplorer" %> 9 <%@ Property Name="SourceDatabase" Type="SchemaExplorer.DatabaseSchema" Category="Context" %> 10 <%@ Property Name="NameSpace" Type="String" Category="参数" Description="命名空间" Default="Blog.Core.Model" Optional="True"%> 11 <%@ Import Namespace="System.Text.RegularExpressions" %> 12 using System; 13 using System.Collections.Generic; 14 using System.Text; 15 16 namespace <%=NameSpace%> 17 { 18 <% foreach(TableSchema SourceTable in SourceDatabase.Tables) { %> 19 ///20 /// <%=GetClassName(SourceTable) +"模型"%> 21 /// 22 [Serializable] 23 public class <%=GetClassName(SourceTable) %> : BaseModel 24 { 25 /// 26 /// 表名 27 /// 28 public static readonly string TableName = "<%=GetClassName(SourceTable) %>"; 29 30 /// 31 /// 构造函数 32 /// 33 public <%=GetClassName(SourceTable) %>() : base(TableName) 34 { 35 } 36 37 private Guid Id = Guid.Empty; 38 <% foreach (ColumnSchema column in SourceTable.Columns) {%> 39 /// 40 /// <%=column.Description %> 41 /// 42 <% if(column.IsPrimaryKeyMember){ %> 43 public Guid <%= GetPascalName(column) %> 44 { 45 get{ return Id;} 46 set 47 { 48 Id = value; 49 if (value != null) 50 { 51 base.BaseId = value; 52 } 53 } 54 } 55 56 <% }else{ %> 57 public <%=GetCSharpVariableType(column) %> <%=GetPascalName(column) %> { get; set; } 58 59 <% } %> 60 <% }%> 61 } 62 63 /// 64 /// <%=GetClassName(SourceTable) +"数据模型"%> 65 /// 66 [Serializable] 67 public class <%=GetClassName(SourceTable)+"ListData" %> 68 { 69 /// 70 /// 总记录数 71 /// 72 public int RecordCount { get; set; } 73 74 /// 75 /// 数据列表 76 /// 77 public List<<%=GetClassName(SourceTable)+"ListModel" %>> RecordList { get; set; } 78 } 79 80 /// 81 /// <%=GetClassName(SourceTable) +"列表模型"%> 82 /// 83 [Serializable] 84 public class <%=GetClassName(SourceTable)+"ListModel" %> 85 { 86 <% foreach (ColumnSchema column in SourceTable.Columns) {%> 87 <%if(new string[]{"IsDeleted"}.Contains(column.Name)){continue;} %> 88 /// 89 /// <%=column.Description %> 90 /// 91 public <%=GetCSharpVariableType(column)=="Guid" || GetCSharpVariableType(column)=="DateTime"?"string":GetCSharpVariableType(column) %> <%=GetPascalName(column) %> { get; set; } 92 93 <% }%> 94 } 95 <%} %> 96 } 97
CodeSmith虽然方便,但是要安装和激活,这个是很麻烦的;而且每次生成都要打开CodeSmith去生成,不是很方便;
于是我就照着原先在CodeSmith上模板写了个控制台应用程序,可以改写配合着bat使用,贼方便
1 using System; 2 using System.Collections.Generic; 3 using System.Data; 4 using System.Data.SqlClient; 5 using System.Text; 6 using System.Linq; 7 using System.IO; 8 9 namespace Blog.Core.Test 10 { 11 public class Program 12 { 13 ///14 /// 数据库连接字符串 15 /// 16 private static string _connstr = "Data Source=localhost;Initial Catalog=Test;User Id=sa;Password=123456"; 17 18 /// 19 /// 主函数 20 /// 21 /// 22 static void Main(string[] args) 23 { 24 Console.Write("命名空间:"); 25 string namespaces = Console.ReadLine(); 26 Console.Write("文件名:"); 27 string filename = Console.ReadLine(); 28 Console.WriteLine("开始生成,请等待..."); 29 new Program().Generate(namespaces, filename); 30 Console.WriteLine("生成成功..."); 31 Console.ReadKey(); 32 } 33 34 /// 35 /// 生成Model文件 36 /// 37 /// 38 /// 39 private void Generate(string namespaces, string filename) 40 { 41 byte[] myByte = Encoding.UTF8.GetBytes(BuildTemplete(namespaces)); 42 string filepath = Environment.CurrentDirectory + "\\" + filename; 43 if (File.Exists(filepath)) 44 { 45 File.Delete(filepath); 46 } 47 using (FileStream fsWrite = new FileStream(filepath, FileMode.Append)) 48 { 49 fsWrite.Write(myByte, 0, myByte.Length); 50 }; 51 } 52 53 /// 54 /// 创建模板 55 /// 56 /// 57 /// 58 private string BuildTemplete(string namespaces) 59 { 60 StringBuilder templete = new StringBuilder("using System;"); 61 templete.Append("using System.Collections.Generic;\n\n"); 62 templete.AppendFormat("namespace {0}\n{{\n", namespaces); 63 List tables = GetTables(); 64 foreach (var table in tables) 65 { 66 templete.AppendFormat(" #region {0}\n", table.name); 67 templete.Append(" /// \n "); 68 templete.AppendFormat(" /// {0}模型\n", table.name); 69 templete.Append(" /// \n"); 70 templete.Append(" [Serializable]\n"); 71 templete.AppendFormat(" public class {0} : BaseModel\n {{", table.name); 72 templete.Append("\n"); 73 templete.Append(" ///\n "); 74 templete.Append(" /// 表名\n"); 75 templete.Append(" /// \n"); 76 templete.AppendFormat(" public static readonly string TableName = \"{0}\";\n", table.name); 77 templete.Append("\n"); 78 templete.Append(" ///\n "); 79 templete.Append(" /// 构造函数\n"); 80 templete.Append(" /// \n"); 81 templete.AppendFormat(" public {0}() : base(TableName) {{ }}\n", table.name); 82 templete.Append(" private Guid Id = Guid.Empty;\n"); 83 table.columns.ForEach(columu => 84 { 85 templete.Append("\n"); 86 templete.Append(" ///\n "); 87 templete.AppendFormat(" /// {0}\n", columu.ColComment); 88 templete.Append(" /// \n"); 89 if (columu.IsPk) 90 { 91 templete.AppendFormat(" public Guid {0}\n", columu.ColName); 92 templete.Append(" {\n"); 93 templete.Append(" get { return Id; }\n"); 94 templete.Append(" set\n"); 95 templete.Append(" {\n"); 96 templete.Append(" Id = value;\n"); 97 templete.Append(" if (value != null)\n"); 98 templete.Append(" {\n"); 99 templete.Append(" base.BaseId = value;\n"); 100 templete.Append(" }\n"); 101 templete.Append(" }\n"); 102 templete.Append(" }\n"); 103 } 104 else 105 { 106 templete.AppendFormat(" public {0} {1} {{ get; set; }} {2}\n", GetCSType(columu.ColType), columu.ColName, GetCSDefault(columu.ColDefault)); 107 } 108 }); 109 templete.Append(" }"); 110 111 templete.Append("\n"); 112 113 templete.Append(" ///\n "); 114 templete.AppendFormat(" /// {0}数据模型\n", table.name); 115 templete.Append(" /// \n"); 116 templete.Append(" [Serializable]\n"); 117 templete.AppendFormat(" public class {0}ListData\n {{", table.name); 118 templete.Append("\n"); 119 templete.Append(" ///\n "); 120 templete.Append(" /// 总记录数\n"); 121 templete.Append(" /// \n"); 122 templete.Append(" public int RecordCount { get; set; }\n"); 123 templete.Append(" ///\n "); 124 templete.Append("\n"); 125 templete.Append(" /// 数据列表\n"); 126 templete.Append(" /// \n"); 127 templete.AppendFormat(" public List<{0}ListModel> RecordList {{ get; set; }}\n", table.name); 128 templete.Append(" }"); 129 130 templete.Append("\n"); 131 132 templete.Append(" ///\n "); 133 templete.AppendFormat(" /// {0}列表模型\n", table.name); 134 templete.Append(" /// \n"); 135 templete.Append(" [Serializable]\n"); 136 templete.AppendFormat(" public class {0}ListModel\n {{", table.name); 137 templete.Append("\n"); 138 table.columns.ForEach(columu => 139 { 140 if (columu.ColName != "IsDeleted") 141 { 142 templete.Append("\n"); 143 templete.Append(" ///\n "); 144 templete.AppendFormat(" /// {0}\n", columu.ColComment); 145 templete.Append(" /// \n"); 146 if (new string[] { "Guid", "DateTime" }.Contains(GetCSType(columu.ColType))) 147 { 148 templete.AppendFormat(" public string {0} {{ get; set; }}\n", columu.ColName); 149 } 150 else 151 { 152 templete.AppendFormat(" public {0} {1} {{ get; set; }}\n", GetCSType(columu.ColType), columu.ColName); 153 } 154 } 155 }); 156 templete.Append(" }\n"); 157 templete.Append(" #endregion\n"); 158 templete.Append("\n"); 159 } 160 templete = templete.Remove(templete.Length - 2, 1); 161 templete.Append("}"); 162 return templete.ToString(); 163 } 164 165 ///166 /// 获取表数据 167 /// 168 /// 169 private List GetTables() 170 { 171 List tables = new List (); 172 DataTable tabName = Query("SELECT name AS TableName FROM sysobjects WHERE xtype = 'U'"); 173 DataTable colName = Query(@"--获取表名、字段名称、字段类型、字段说明、字段默认值 174 SELECT obj.name AS TableName,--表名 175 col.name AS ColName,--列名 176 typ.name AS ColType,--字段类型 177 cmt.value AS ColComment,--字段说明 178 dft.text AS ColDefault--字段默认值 179 FROM syscolumns col--字段 180 INNER JOIN sysobjects obj--表 181 ON col.id = obj.id 182 AND obj.xtype = 'U'--表示用户表 183 LEFT JOIN systypes typ--类型 184 ON col.xtype = typ.xusertype 185 LEFT JOIN sys.extended_properties cmt--字段说明 186 ON col.id = cmt.major_id--表Id 187 AND col.colid = cmt.minor_id--字段Id 188 LEFT JOIN syscomments dft--默认值 189 ON col.cdefault = dft.id 190 ORDER BY obj.name, 191 col.id ASC 192 "); 193 DataTable pk = Query(@"--获取表的主键字段名 194 SELECT CCU.COLUMN_NAME, 195 TC.TABLE_NAME 196 FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS TC 197 INNER JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE CCU 198 ON TC.CONSTRAINT_NAME = CCU.CONSTRAINT_NAME 199 WHERE TC.CONSTRAINT_TYPE = 'PRIMARY KEY' 200 "); 201 foreach (DataRow row in tabName.Rows) 202 { 203 TableModel table = new TableModel(); 204 table.name = row["TableName"].ToString(); ; 205 table.columns = new List (); 206 DataRow[] cols = colName.Select(string.Format("TableName = '{0}'", row["TableName"].ToString())); 207 DataRow[] pks = pk.Select(string.Format("TABLE_NAME = '{0}'", row["TableName"].ToString())); 208 string primarykey = pks == null || pks.Length == 0 ? "" : pks[0]["COLUMN_NAME"].ToString(); 209 foreach (DataRow col in cols) 210 { 211 ColumnModel column = new ColumnModel(); 212 column.IsPk = primarykey == col["ColName"].ToString(); 213 column.ColName = col["ColName"].ToString(); 214 column.ColType = col["ColType"].ToString(); 215 column.ColComment = col["ColComment"].ToString(); 216 column.ColDefault = col["ColDefault"].ToString(); 217 table.columns.Add(column); 218 } 219 tables.Add(table); 220 } 221 return tables; 222 223 } 224 225 /// 226 /// 简单的SQL查询 227 /// 228 /// 229 /// 230 private DataTable Query(string sqlString) 231 { 232 DataTable dt = new DataTable(); 233 using (SqlConnection conn = new SqlConnection(_connstr)) 234 { 235 using (SqlCommand command = conn.CreateCommand()) 236 { 237 command.CommandText = sqlString; 238 SqlDataAdapter adapter = new SqlDataAdapter(); 239 adapter.SelectCommand = command; 240 adapter.Fill(dt); 241 } 242 } 243 return dt; 244 } 245 246 /// 247 /// 获取C#类型 248 /// 249 /// 250 /// 251 private string GetCSType(string sqlType) 252 { 253 switch (sqlType) 254 { 255 case "datetime": 256 return "DateTime"; 257 case "int": 258 return "int"; 259 case "nchar": 260 return "string"; 261 case "nvarchar": 262 return "string"; 263 case "varchar": 264 return "string"; 265 case "text": 266 return "string"; 267 case "ntext": 268 return "string"; 269 case "uniqueidentifier": 270 return "Guid"; 271 case "decimal": 272 return "decimal"; 273 case "float": 274 return "float"; 275 case "bit": 276 return "byte"; 277 case "binary": 278 return "byte []"; 279 case "varbinary": 280 return "byte []"; 281 case "timestamp": 282 return "int"; 283 default: 284 return ""; 285 } 286 } 287 288 /// 289 /// 获取C#默认值 290 /// 291 /// 292 /// 293 private string GetCSDefault(string sqlValue) 294 { 295 switch (sqlValue) 296 { 297 case "((0))": 298 return "= 0;"; 299 case "('')": 300 return "= string.Empty;"; 301 case "('00000000-0000-0000-0000-000000000000')": 302 return "= Guid.Empty;"; 303 default: 304 return ""; 305 } 306 } 307 } 308 309 /// 310 /// 表模型 311 /// 312 public class TableModel 313 { 314 /// 315 /// 表名 316 /// 317 public string name { get; set; } 318 319 /// 320 /// 表字段 321 /// 322 public List columns { get; set; } 323 } 324 325 /// 326 /// 字段模型 327 /// 328 public class ColumnModel 329 { 330 /// 331 /// 是否主键 332 /// 333 public bool IsPk { get; set; } 334 335 /// 336 /// 列名 337 /// 338 public string ColName { get; set; } 339 340 /// 341 /// 列类型 342 /// 343 public string ColType { get; set; } 344 345 /// 346 /// 列说明 347 /// 348 public string ColComment { get; set; } 349 350 /// 351 /// 列默认值 352 /// 353 public string ColDefault { get; set; } 354 } 355 }