三、T4模板与实体生成

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

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

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

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

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

<#+
//数据库操作
public static class DBHelper
{
    private static SqlCommand PrepareCommand(SqlConnection conn, string cmdText, CommandType cmdType, SqlParameter[] parameters)
    {
        if (conn.State != ConnectionState.Open)
        {
            conn.Open();
        }
        SqlCommand cmd = new SqlCommand(cmdText, conn);
        cmd.CommandType = cmdType;
        if (parameters != null)
        {
            cmd.Parameters.Clear();
            cmd.Parameters.AddRange(parameters);
        }

        return cmd;
    }

    public static DataSet GetDataSet(string connString,string strSQL)
    {
        using (SqlConnection conn = new SqlConnection(connString))
        {
            SqlDataAdapter da = new SqlDataAdapter(strSQL, conn);
            DataSet ds = new DataSet();
            da.Fill(ds);
            return ds;
        }
    }

    public static DataSet GetSchemaInfo(string connString,string tableName)
    {
            StringBuilder sbSQL = new StringBuilder();
            sbSQL.AppendLine("SELECT ");
            sbSQL.AppendLine("    [Id]=C.column_id,");
            sbSQL.AppendLine("    [Name]=C.name,");
            sbSQL.AppendLine("    [Type]=T.name,");
            sbSQL.AppendLine("    [Length]=C.max_length,");
            sbSQL.AppendLine("    [Identity]=CASE WHEN C.is_identity=1 THEN N‘T‘ELSE N‘‘ END,");
            sbSQL.AppendLine("    [PrimaryKey]=ISNULL(PKInfo.PrimaryKey,N‘‘),");
            sbSQL.AppendLine("    [ForeignKey]=CASE WHEN FKInfo.parent_column_id>0 THEN N‘T‘ELSE N‘‘ END,");
            sbSQL.AppendLine("    [ForeignKeyTable]=ISNULL(FKInfo.name,N‘‘),");
            sbSQL.AppendLine("    [IsNull]=CASE WHEN C.is_nullable=1 THEN N‘T‘ELSE N‘‘ END,");
            sbSQL.AppendLine("    [Default]=ISNULL(DC.definition,N‘‘),");
            sbSQL.AppendLine("    [ColumnDesc]=ISNULL(EP.value,N‘‘) ");
            sbSQL.AppendLine("FROM sys.columns C ");
            sbSQL.AppendLine("INNER JOIN sys.objects O ON C.object_id=o.object_id AND O.type=‘U‘ AND O.is_ms_shipped=0 ");
            sbSQL.AppendLine("INNER JOIN sys.types T ON C.user_type_id=T.user_type_id ");
            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 ");
            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 ");
            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 ");
            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 ");
            sbSQL.AppendFormat("WHERE O.name=‘{0}‘ ORDER BY Id ASC", tableName);
            return GetDataSet(connString,sbSQL.ToString());
    }
}

//类型转换
public static class TypeConvertor
{
    //将数据库类型映射成C#类型
    public static string MapType(string dbType)
    {
        if (string.IsNullOrEmpty(dbType)) return dbType;
        dbType = dbType.ToLower();
        string csType = "object";
        switch (dbType)
        {
            case "char": csType = "string"; break;
            case "date": csType = "DateTime"; break;
            case "datetime": csType = "DateTime"; break;
            case "decimal": csType = "decimal"; break;
            case "float": csType = "double"; break;
            case "int": csType = "int"; break;
            case "money": csType = "decimal";break;
            case "nchar": csType = "string"; break;
            case "ntext": csType = "string"; break;
            case "nvarchar": csType = "string"; break;
            case "smalldatetime": csType = "DateTime"; break;
            case "smallint": csType = "short"; break;
            case "smallmoney": csType = "decimal"; break;
            case "text": csType = "string"; break;
            case "time": csType = "TimeSpan"; break;
            case "varchar": csType = "string"; break;
            default: csType = "object"; break;
        }
        return csType;
    }
}
#>

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

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Data" #>
<#@ assembly name="System.Xml" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Data" #>
<#@ import namespace="System.Data.SqlClient" #>
<#@ import namespace="System.Xml" #>
<#@ output extension=".cs" #>
<#@ include file="$(ProjectDir)Utility.tt" #>
<#
    string connString="Data Source=192.168.1.101;Database=DB_Test;uid=sa;pwd=123";
    string tableName="Base_Person";
    string nameSpace="EntityGenerator";
#>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace <#=nameSpace  #>
{
    public class <#= tableName #>Entity
    {
<#
DataTable dt = DBHelper.GetSchemaInfo(connString,tableName).Tables[0];
foreach(DataRow dr in dt.Rows)
{
 #>
        /// <summary>
        /// <#= dr["ColumnDesc"].ToString() #>
        /// </summary>
        public <#= TypeConvertor.MapType(dr["Type"].ToString()) #> <#= dr["Name"].ToString() #> { get; set; }

<# } #>
    }
}

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

<#@ assembly name="System.Core" #>
<#@ assembly name="System.Data" #>
<#@ assembly name="System.Xml" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Data" #>
<#@ import namespace="System.Data.SqlClient" #>
<#@ import namespace="System.Xml" #>

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

<#
    string connString="Data Source=192.168.1.101;Database=MicroERP;uid=sa;[email protected]#";
    string tableName="Base_Person";
    string nameSpace="EntityGenerator";
#>

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

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

<#
DataTable dt = DBHelper.GetSchemaInfo(connString,tableName).Tables[0];
foreach(DataRow dr in dt.Rows)
{
 #>
        /// <summary>
        /// <#= dr["ColumnDesc"].ToString() #>
        /// </summary>
        public <#= TypeConvertor.MapType(dr["Type"].ToString()) #> <#= dr["Name"].ToString() #> { get; set; }

<# } #>

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

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

源码下载

时间: 2024-10-07 13:39:24

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

[转]MVC实用架构设计(三)——EF-Code First(3):使用T4模板生成相似代码

本文转自:http://www.cnblogs.com/guomingfeng/p/mvc-ef-t4.html 〇.目录 一.前言 二.工具准备 三.T4代码生成预热 (一) 单文件生成:HelloWorld.cs (二) 多文件生成 四.生成数据层实体相关相似代码 (一) 生成准备 (二) 生成实体相关相似代码 生成实体映射配置类 生成实体仓储接口 生成实体仓储实现 五.源码获取 系列导航 一.前言 经过前面EF的<第一篇>与<第二篇>,我们的数据层功能已经较为完善了,但有不少

轻量级ORM 利用T4模板 批量生成多文件 实体和业务逻辑 代码

FluentData,它是一个轻量级框架,关注性能和易用性. 下载地址:FlunenData.Model 利用T4模板,[MultipleOutputHelper.ttinclude]批量生成多文件 基本语法: 1. 初始化:获取MultipleOutputHelper.ttinclude文件模板 在T4模板导入 //导入MultipleOutputHelper.ttinclude文件 路径 <#@include file="$(SolutionDir)\ORM.Model\T4\Mult

T4模板_根据DB生成实体类

为了减少重复劳动,可以通过T4读取数据库表结构,生成实体类,用下面的实例测试了一下 1.首先创建一个项目,并添加文本模板: 2.添加 文本模板: 3.向T4文本模板文件添加代码: <#@ template language="C#" debug="True" hostspecific="True" #> <#@ assembly name="System.Data" #> <#@ assembly

T4 模板自动生成带注释的实体类文件 - 只需要一个 SqlSugar.dll

生成实体就是这么简单,只要建一个T4文件和 文件夹里面放一个DLL. 使用T4模板教程 步骤1 创建T4模板 ,一定要自已新建,把T4代码复制进去,好多人因为用我现成的T4报错(原因不明) 点击添加文件,选择[ 运行时文本模版](后缀为 .tt)取个名字点确定. 步骤2 设置当前T4所需要的序集并且引用 SqlSugar.dll 编写连接数据库代码 调用SqlSugar生成实体函数,填写参数. 图片看不清楚看下面代码 <#@ template debug="false" host

使用T4模板为EF框架添加实体根据数据库自动生成字段注释的功能

在以往的开发过程当中,我会经常选择EF框架作为底层数据结构,EF为我们提供了很好的ado.net数据访问机制,他覆盖了数据链接,linq等多方面内容,而且当我们使用数据库优先或者code first的时候都体现出明显的优势. 一键生成实体,免除手写model的烦恼. 实时更新数据结构,使数据库与model保持高度一致. 提供多种底层数据的访问方法. 优雅的语法,对于我这种喜爱偷懒的程序猿是一大福音. 然而entity framework在vs中生成的.edmx文件,会导致摘要(说明)为空的bug

Visual Studio 2013 EF5实体数据模型 EDMX 使用 T4模板生成后使用 ObjectContext对象

Visual Studio 2013 EF5实体数据模型 EDMX 使用 T4模板生成后的继承对象为DbContext,以前的熟悉的ObjectContext对象不见了,当然使用ObjectContext对象不是每个程序员都需要的,解决办法有两种: 方法1.打开Model.Context.cs,添加 public OracleModelEntities(ObjectContext objectContext, bool dbContextOwnsObjectContext)           

C#集合篇,在业务背景下(***产品升级管理):依赖注入,变量声明,三元表达式,常用字符串相关操作方法,ADO.NET,EF机制,T4模板自动生成实体类,ref变量巧用,属性实际运用,唯一性验证

QQ:1187362408 欢迎技术交流和学习 关于系统产品升级报告管理,业务需求: TODO: 1,升级报告管理:依据各县区制定升级报告(关联sAreaCode,给每个地区观看具体升级报告信息) 2,运用的技术:依赖注入,变量声明,三元表达式,常用字符串相关操作方法,ADO.NET,EF机制,T4模板自动生成实体类,ref变量与可null变量巧用,属性实际运用,唯一性验证,url传递中文编码和解码问题 讲解篇:1,服务端aspx,2,服务端后台返回数据(这里采用服务器端程序:aspx.cs)

C# Net MVC+SqlServer=T4模板生成实体类并操作数据(DbHelper+DBManage)

1.ConnectionString,数据库链接 Web.config <configuration> <connectionStrings> <!-- 数据库 SQL Server --> <add name="ConnectionString" connectionString="Data Source=**IP地址**;Initial Catalog=**数据库名**;User ID=**用户名**;Password=**密码*

从零开始编写自己的C#框架(14)——T4模板在逻辑层中的应用(三)

原本关于T4模板原想分5个章节详细解说的,不过因为最近比较忙,也不想将整个系列时间拉得太长,所以就将它们整合在一块了,可能会有很多细节没有讲到,希望大家自己对着代码与模板去研究. 本章代码量会比较大,基本将Web层要使用到的大部分函数都用模板生成了出来,而模板中的函数,很多也是互相关联调用的.另外在DotNet.Utilities(公共函数项目)中也添加与修改了一些类和函数. 需要特别说明的是,在逻辑层添加了July大神编写的超强上传类,具体怎么使用功能怎么强大,在后面调用到时会用一个章节详细说