上文我们最后虽然用模板创建了一个实体类,但是类的内容仍旧是静态的,这里我们需要用动态方式生成类的内容。因为需要查询数据库这里又免不了各种繁琐的连接数据库操作,为了使我们的编码更加直观,仍然采用C#编码习惯来书写T4代码。

     在JSP中,我们可以使用include标签来包含另一个JSP文件。在T4模板中也可以在一个模板文件中包含另一个模板文件。所以我们尽可能把公共模块的代码提取到一个T4模板文件中,方便重复使用。包含指令如下:

  1. <#@ include file="$(ProjectDir)IncludeFile.tt" #>

使用的@ include指令。其中$(ProjectDir)是宏变量,指代当前项目工程路径。

首先创建一个Utility.tt模板文件,该文件主要放一些常用的工具类如DBHelper等,因为工具类只在调用时才执行,而.tt文件在保存时就执行,所以每次保存该文件都会执行里面的代码很繁琐,可以右击该文件【属性】把【自定义工具】中:TextTemplatingFileGenerator属性去掉。这样该模板保存时就不会执行。(注:关于设计时模板和运行时模板的区别和用途这里就不做介绍,这样做主要把问题简化)完整代码如下:

  1. <#+
  2. //数据库操作
  3. public static class DBHelper
  4. {
  5. private static SqlCommand PrepareCommand(SqlConnection conn, string cmdText, CommandType cmdType, SqlParameter[] parameters)
  6. {
  7. if (conn.State != ConnectionState.Open)
  8. {
  9. conn.Open();
  10. }
  11. SqlCommand cmd = new SqlCommand(cmdText, conn);
  12. cmd.CommandType = cmdType;
  13. if (parameters != null)
  14. {
  15. cmd.Parameters.Clear();
  16. cmd.Parameters.AddRange(parameters);
  17. }
  18.  
  19. return cmd;
  20. }
  21.  
  22. public static DataSet GetDataSet(string connString,string strSQL)
  23. {
  24. using (SqlConnection conn = new SqlConnection(connString))
  25. {
  26. SqlDataAdapter da = new SqlDataAdapter(strSQL, conn);
  27. DataSet ds = new DataSet();
  28. da.Fill(ds);
  29. return ds;
  30. }
  31. }
  32.  
  33. public static DataSet GetSchemaInfo(string connString,string tableName)
  34. {
  35. StringBuilder sbSQL = new StringBuilder();
  36. sbSQL.AppendLine("SELECT ");
  37. sbSQL.AppendLine(" [Id]=C.column_id,");
  38. sbSQL.AppendLine(" [Name]=C.name,");
  39. sbSQL.AppendLine(" [Type]=T.name,");
  40. sbSQL.AppendLine(" [Length]=C.max_length,");
  41. sbSQL.AppendLine(" [Identity]=CASE WHEN C.is_identity=1 THEN N'T'ELSE N'' END,");
  42. sbSQL.AppendLine(" [PrimaryKey]=ISNULL(PKInfo.PrimaryKey,N''),");
  43. sbSQL.AppendLine(" [ForeignKey]=CASE WHEN FKInfo.parent_column_id>0 THEN N'T'ELSE N'' END,");
  44. sbSQL.AppendLine(" [ForeignKeyTable]=ISNULL(FKInfo.name,N''),");
  45. sbSQL.AppendLine(" [IsNull]=CASE WHEN C.is_nullable=1 THEN N'T'ELSE N'' END,");
  46. sbSQL.AppendLine(" [Default]=ISNULL(DC.definition,N''),");
  47. sbSQL.AppendLine(" [ColumnDesc]=ISNULL(EP.value,N'') ");
  48. sbSQL.AppendLine("FROM sys.columns C ");
  49. sbSQL.AppendLine("INNER JOIN sys.objects O ON C.object_id=o.object_id AND O.type='U' AND O.is_ms_shipped=0 ");
  50. sbSQL.AppendLine("INNER JOIN sys.types T ON C.user_type_id=T.user_type_id ");
  51. sbSQL.AppendLine("LEFT JOIN sys.default_constraints DC ON C.object_id=DC.parent_object_id AND C.column_id=DC.parent_column_id AND C.default_object_id=DC.object_id ");
  52. sbSQL.AppendLine("LEFT JOIN sys.extended_properties EP ON EP.class=1 AND C.object_id=EP.major_id AND C.column_id=EP.minor_id ");
  53. sbSQL.AppendLine("LEFT JOIN (SELECT IC.object_id,IC.column_id,PrimaryKey=CASE WHEN I.is_primary_key=1 THEN N'T'ELSE N'' END FROM sys.indexes I INNER JOIN sys.index_columns IC ON I.[object_id]=IC.[object_id] AND I.index_id=IC.index_id)PKInfo ON PKInfo.object_id=C.object_id AND PKInfo.column_id=C.column_id ");
  54. sbSQL.AppendLine("LEFT JOIN (SELECT FKC.parent_object_id,FKC.parent_column_id,O.name FROM sys.foreign_key_columns FKC INNER JOIN sys.objects O ON FKC.referenced_object_id=O.object_id)FKInfo ON C.object_id=FKInfo.parent_object_id AND C.column_id=FKInfo.parent_column_id ");
  55. sbSQL.AppendFormat("WHERE O.name='{0}' ORDER BY Id ASC", tableName);
  56. return GetDataSet(connString,sbSQL.ToString());
  57. }
  58. }
  59.  
  60. //类型转换
  61. public static class TypeConvertor
  62. {
  63. //将数据库类型映射成C#类型
  64. public static string MapType(string dbType)
  65. {
  66. if (string.IsNullOrEmpty(dbType)) return dbType;
  67. dbType = dbType.ToLower();
  68. string csType = "object";
  69. switch (dbType)
  70. {
  71. case "char": csType = "string"; break;
  72. case "date": csType = "DateTime"; break;
  73. case "datetime": csType = "DateTime"; break;
  74. case "decimal": csType = "decimal"; break;
  75. case "float": csType = "double"; break;
  76. case "int": csType = "int"; break;
  77. case "money": csType = "decimal";break;
  78. case "nchar": csType = "string"; break;
  79. case "ntext": csType = "string"; break;
  80. case "nvarchar": csType = "string"; break;
  81. case "smalldatetime": csType = "DateTime"; break;
  82. case "smallint": csType = "short"; break;
  83. case "smallmoney": csType = "decimal"; break;
  84. case "text": csType = "string"; break;
  85. case "time": csType = "TimeSpan"; break;
  86. case "varchar": csType = "string"; break;
  87. default: csType = "object"; break;
  88. }
  89. return csType;
  90. }
  91. }
  92. #>

该文件把自动生成的指令标签全部去掉了,只用了<#+ #>标签来包含代码块。该文件中包含两个类:DBHelper和TypeConvertor,为了方便演示我简化了这些类中的代码,只留了需要用到的方法。接下来打开原来的EntityTemplate.tt文件修改代码如下:

  1. <#@ template debug="false" hostspecific="false" language="C#" #>
  2. <#@ assembly name="System.Core" #>
  3. <#@ assembly name="System.Data" #>
  4. <#@ assembly name="System.Xml" #>
  5. <#@ import namespace="System.Linq" #>
  6. <#@ import namespace="System.Text" #>
  7. <#@ import namespace="System.Collections.Generic" #>
  8. <#@ import namespace="System.Data" #>
  9. <#@ import namespace="System.Data.SqlClient" #>
  10. <#@ import namespace="System.Xml" #>
  11. <#@ output extension=".cs" #>
  12. <#@ include file="$(ProjectDir)Utility.tt" #>
  13. <#
  14. string connString="Data Source=192.168.1.101;Database=DB_Test;uid=sa;pwd=123";
  15. string tableName="Base_Person";
  16. string nameSpace="EntityGenerator";
  17. #>
  18. using System;
  19. using System.Collections.Generic;
  20. using System.Linq;
  21. using System.Text;
  22.  
  23. namespace <#=nameSpace #>
  24. {
  25. public class <#= tableName #>Entity
  26. {
  27. <#
  28. DataTable dt = DBHelper.GetSchemaInfo(connString,tableName).Tables[0];
  29. foreach(DataRow dr in dt.Rows)
  30. {
  31. #>
  32. /// <summary>
  33. /// <#= dr["ColumnDesc"].ToString() #>
  34. /// </summary>
  35. public <#= TypeConvertor.MapType(dr["Type"].ToString()) #> <#= dr["Name"].ToString() #> { get; set; }
  36.  
  37. <# } #>
  38. }
  39. }

该文件中使用<#@ include file="$(ProjectDir)Utility.tt" #>来包含上述定义的Utility模板。

  1. <#@ assembly name="System.Core" #>
  2. <#@ assembly name="System.Data" #>
  3. <#@ assembly name="System.Xml" #>
  4. <#@ import namespace="System.Linq" #>
  5. <#@ import namespace="System.Text" #>
  6. <#@ import namespace="System.Collections.Generic" #>
  7. <#@ import namespace="System.Data" #>
  8. <#@ import namespace="System.Data.SqlClient" #>
  9. <#@ import namespace="System.Xml" #>

这里添加数据库操作类需要使用的程序集和命名空间。

  1. <#
  2. string connString="Data Source=192.168.1.101;Database=MicroERP;uid=sa;pwd=123qwe!@#";
  3. string tableName="Base_Person";
  4. string nameSpace="EntityGenerator";
  5. #>

这里我们把需要用的变量提成全局,以方便后面变更数据库、项目时修改。

<#= #>这和ASP.NET一样为输出表达式。

  1. <#
  2. DataTable dt = DBHelper.GetSchemaInfo(connString,tableName).Tables[0];
  3. foreach(DataRow dr in dt.Rows)
  4. {
  5. #>
  6. /// <summary>
  7. /// <#= dr["ColumnDesc"].ToString() #>
  8. /// </summary>
  9. public <#= TypeConvertor.MapType(dr["Type"].ToString()) #> <#= dr["Name"].ToString() #> { get; set; }
  10.  
  11. <# } #>

这里就是连接数据库获取到表结构,再根据表结构,动态生成类的属性,注释,以及数据库类型转化为C#类型。保存该模板效果如下:

这样一个完整的实体类就动态生成了,关于获取数据库表结构,后面将花一整个篇幅来讲解不同数据库怎么提取表结构。估计也有可能放在ORM框架中讲解,这里仅仅先演示其作用。

源码下载

三、T4模板与实体生成的更多相关文章

  1. T4模板根据DB生成实体类

    1.前言 为什么会有这篇文章了,最近看到了一些框架,里面要写的代码太多了,故此就想偷懒,要是能写出一个T4模板,在数据库添加表后,根据模板就可以自动生成了类文件了,这样多好,心动不如行动.记得使用T4 ...

  2. 自定义T4模板去掉实体对象中的下划线

            在EF Power Tool 默认使用的T4模板中,如果数据库表有下划线,那么生成的实体也有下划线,但是我们实际使用的过程中,是不希望有下划线的,要解决这个问题,可以自定义这个T4模板 ...

  3. c# 利用t4模板,自动生成Model类

    我们在用ORM(比如dapper)的时候,很多时候都需要自己写Model层(当然也有很多orm框架自带了这种功能,比如ef),特别是表里字段比较多的时候,一个Model要写半天,而且Model如果用于 ...

  4. C# T4 模板 数据库实体类生成模板(带注释,娱乐用)

     说明:..,有些工具生成实体类没注释,不能和SqlServer的MS_Description属性一起使用,然后照着网上的资源,随便写了个生成模板,自娱自乐向,其实卵用都没有参考教程    1.htt ...

  5. EF t4模板将实体与DBContext分离

    在用EF DBFirst时,实体类是从数据库自动生成的,与DBContext放在同一个项目中.这样其他项目想引用实体,就会将数据库操作类暴露出来.所以,我们需要将实体分离. 新建项目EFAccess, ...

  6. 使用T4模板生成POCO类

    为什么叫T4?因为简写为4个T. T4(Text Template Transformation Toolkit)是微软官方在VisualStudio 2008中开始使用的代码生成引擎.在 Visua ...

  7. Asp.Net T4模板生成三层架构

    1.T4 Editor安装 T4:根据模板生成文件,例如model等 vs中默认t4模板编码是没有提示和高亮的,需使用以下插件,免费的 https://t4-editor.tangible-engin ...

  8. 【VS外接程序】利用T4模板生成模块代码

    引言 记得第一次做asp.net mvc项目时,可以用model直接生成Html的增删改查页面, 没什么特殊要求都可以不用修改直接用了, 觉得很神奇,效率太高了.后来在做客户端开发时,发现很多模块都是 ...

  9. NFine框架的T4模板

    1.前言 前段时间在网上看到一个开源框架很好的.开源:ASP.NET MVC+EF6+Bootstrap开发框架,写代码就是比较比较麻烦,分层比较多,对于我这种偷懒的人就想到了写一个T4模板.不了解框 ...

随机推荐

  1. 专家解读Linux操作系统内核中的GCC特性

    专家解读Linux操作系统内核中的GCC特性   Linux内核使用GNU Compiler Collection (GCC)套件的几个特殊功能.这些功能包括提供快捷方式和简化以及向编译器提供优化提示 ...

  2. 跨平台网络通信与服务器框架 acl 3.2.0 发布

    acl 3.2.0 版本发布了,acl 是 one advanced C/C++ library 的简称,主要包括网络通信库以及服务器框架库等功能,支持 Linux/Windows/Solaris/F ...

  3. List、Set、 数组等转字符串

    public class Test { public static void main(String[] args) { String str = ""; // list转字符串 ...

  4. AES加密跨平台出现的问题

    javax.crypto.BadPaddingException: Given final block not properly padded at com.sun.crypto.provider.S ...

  5. HDU 1495 非常可乐 BFS 搜索

    http://acm.hdu.edu.cn/showproblem.php?pid=1495 题目就不说了, 说说思路! 倒可乐 无非有6种情况: 1. S 向 M 倒 2. S 向 N 倒 3. N ...

  6. 【最短路】NEERC15 F Froggy Ford(2015-2016 ACM-ICPC)(Codeforces GYM 100851)

    题目链接: http://codeforces.com/gym/100851 题目大意: 一只青蛙跳过宽为W的河,河中游N个石头,坐标xi,yi,现在往河中间添加一个石头,使得每次跳跃的最大的距离最小 ...

  7. 【最短路】BAPC2014 B Button Bashing (Codeforces GYM 100526)

    题目链接: http://codeforces.com/gym/100526 http://acm.hunnu.edu.cn/online/?action=problem&type=show& ...

  8. oracle 表的管理(数据类型,表创建删除,数据CRUD 操作)

    表名和列的命名规则

  9. JQuery固定表头插件fixedtableheader源码注释

    在开发XX车站信息系统时,需要将大量数据显示在一个巨大的表格内部,由于表格是一个整体,无法分页,加之数据很多,超出一屏,为了方便用户,决定使用固定表头的插件,经过测试,发现JQuery 插件:fixe ...

  10. Vagrant网络配置

    Vagrant中网络配置 一.基本配置 Vagrant offers multiple options for how you are able to connect your guest machi ...