• 【T4实践(三)】如果更快更好的编写T4模板


    如何快速高效的写出高质量的T4模板呢?

    一、总结:先验证C#代码,然后转T4模板!

    通过实践,总结如下:先验证C#代码,然后转T4模板!
    因为T4模板难以调试,以后会就调试,专门拿一张来介绍。T4模板编写的实质就是脚本代码和文本。脚本代码通常就是C#和VB.Net。主要逻辑都在脚本代码中。而C#代码调试要简单方便的多。所以,在编写T4模板的时候,我们完全,可以先写C#代码,然后再修改为T4模板。需要修改的地方,只是将C#放在<##>标记中,一些引用需要修改,而模板还有个好处,就是不用定义类型,直接添加默认函数或者属性

    本文将结合实际例子,来进行说明。

    二、实例:代码生成器

    该实例,就是我们通常见过的,模型代码生成器,根据数据模型生成代码框架,如模型层、数据访问层等。

    本实例先根据数据表,生存模型层代码。这是一个简单实例,如果有功夫,您可以根据这个原理写出自己的代码生成框架。

    三、具体步骤:

    1、预置数据

    --创建库
    CREATE DATABASE TestDB


    --创建表
    CREATE TABLE PersonInfo
    (
    ID INT PRIMARY KEY NOT NULL,
    NAME nvarchar(50) NOT NULL,
    Company NVARCHAR(50) NULL,
    Job NVARCHAR(20) NULL
    )

    2、写C#代码,并验证通过。可用Console程序验证

    模型管理器:主要实现,数据访问、获取表结构

    using System;
    using System.Data.SqlClient;
    using System.Data;

    namespace T4_3FiledGenerator
    {
    public class ModelManager
    {
    /// <summary>
    /// 数据库连接字符串
    /// </summary>
    private const string CONNECTION_STRING= "server=localhost;database=testDB;uid=sa;pwd=ufsoft;";
    /// <summary>
    /// 用户信息表名
    /// </summary>
    private const string PERSONINFO_TABLE_NAME = "PersonInfo";
    /// <summary>
    /// 根据表名查询表结构信息
    /// </summary>
    private const string SELECT_SCHEMA_BY_TABLE_NAME = @"SELECT TABLE_NAME AS TableName ,
    ORDINAL_POSITION AS ColumnID ,
    COLUMN_NAME AS ColumnName ,
    DATA_TYPE AS DataType ,
    CASE WHEN IS_NULLABLE = 'NO' THEN 'false'
    ELSE 'true'
    END AS IsNullable
    FROM INFORMATION_SCHEMA.COLUMNS AS A
    LEFT JOIN sysobjects AS B ON A.TABLE_NAME = B.name
    WHERE A.TABLE_NAME = '{0}'
    ";

    /// <summary>
    /// 获得数据连接
    /// </summary>
    /// <returns></returns>
    private SqlConnection GetConnection()
    {
    return new SqlConnection(CONNECTION_STRING);
    }
    /// <summary>
    /// 释放连接
    /// </summary>
    /// <param name="con"></param>
    private void ReleaseConnection(SqlConnection con)
    {
    if (con != null)
    {
    if (con.State == ConnectionState.Open)
    {
    con.Close();
    }
    }
    }

    /// <summary>
    ///
    /// </summary>
    /// <param name="tableName"></param>
    public DataTable GetTableSchema(string tableName)
    {
    DataTable dt;
    using (SqlConnection con = GetConnection())
    {
    con.Open();

    SqlCommand cmd = con.CreateCommand();
    cmd.CommandText = string.Format(SELECT_SCHEMA_BY_TABLE_NAME,tableName);
    cmd.CommandType = CommandType.Text;

    SqlDataAdapter adapter = new SqlDataAdapter(cmd);
    DataSet ds = new DataSet();
    adapter.Fill(ds);
    dt = ds.Tables[0];
    }

    return dt;
    }
    /// <summary>
    ///
    /// </summary>
    public void Generate()
    {
    DataTable table = GetTableSchema(PERSONINFO_TABLE_NAME);

    if (table != null && table.Rows.Count > 0)
    {
    foreach (DataRow row in table.Rows)
    {
    Console.WriteLine("public class {0}", row["TableName"]);
    Console.WriteLine("public {0} {1}", TransFromSqlType(row["DataType"].ToString()), row["ColumnName"]);
    }
    }
    }
    /// <summary>
    /// SQL
    /// </summary>
    /// <param name="type"></param>
    /// <returns></returns>
    public string TransFromSqlType(string type)
    {
    if (string.IsNullOrEmpty(type))
    {
    return string.Empty;
    }

    if (string.Equals(type, "int", StringComparison.OrdinalIgnoreCase))
    {
    return "int";
    }
    else if (string.Equals(type, "nvarchar", StringComparison.OrdinalIgnoreCase))
    {
    return "string";
    }

    return "string";
    }

    }
    }

    测试程序:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    namespace T4_3FiledGenerator
    {
    class Program
    {
    static void Main(string[] args)
    {
    ModelManager manager = new ModelManager();
    manager.Generate();
    }
    }
    }


    3、C#代码转换成T4

    3.1 添加引用,在C#中一般都是直接用using,在这里,需要改为import方式,如:<#@ import namespace="System.Data" #>
    如果有些dll,需要添加引用,则需要assembly,如:<#@ assembly name="System.Data" #>。

    对于程序集的加载,通常有两种情况,

    (1)如果C#自带的,则直接用dll的名称即可,

    (2)如果实自定义DLL文件,需要添加全路径,这是最简单的方法,还有其他一些方法,这里暂且不讨论。

    3.2 将写成的C#代码,放在<#+ #>标签中,一般放置在T4模板最后

    3.3 调用C#的方法,初始化变量

    3.4 编写T4文本模板

    3.5 对模板中的一些变量,调用2.3初始化的变量进行赋值

    具体的T4代码如下:

    <#@ template debug="false" hostspecific="false" language="C#" #>
    <#@ output extension=".cs" #>
    <#@ assembly name="System.Data" #>
    <#@ assembly name="System.Xml" #>
    <#@ import namespace="System" #>
    <#@ import namespace="System.Xml" #>
    <#@ import namespace="System.Data" #>
    <#@ import namespace="System.Data.SqlClient" #>
    <#
    ModelManager manager = new ModelManager();
    string tableName = "PersonInfo";
    DataTable table= manager.GetTableSchema(tableName);
    #>
    using System;

    namespace Model
    {
    public class <#= tableName #>
    {
    <#
    foreach(DataRow row in table.Rows)
    {
    #>
    public <#= manager.TransFromSqlType(row["DataType"].ToString())#> <#=row["ColumnName"]#>{ get; set; }

    <#}
    #>
    }
    }

    <#+
    public class ModelManager
    {
    /// <summary>
    /// 数据库连接字符串
    /// </summary>
    private const string CONNECTION_STRING= "server=localhost;database=testDB;uid=sa;pwd=ufsoft;";
    /// <summary>
    /// 用户信息表名
    /// </summary>
    private const string PERSONINFO_TABLE_NAME = "PersonInfo";
    /// <summary>
    /// 根据表名查询表结构信息
    /// </summary>
    private const string SELECT_SCHEMA_BY_TABLE_NAME = @"SELECT TABLE_NAME AS TableName ,
    ORDINAL_POSITION AS ColumnID ,
    COLUMN_NAME AS ColumnName ,
    DATA_TYPE AS DataType ,
    CASE WHEN IS_NULLABLE = 'NO' THEN 'false'
    ELSE 'true'
    END AS IsNullable
    FROM INFORMATION_SCHEMA.COLUMNS AS A
    LEFT JOIN sysobjects AS B ON A.TABLE_NAME = B.name
    WHERE A.TABLE_NAME = '{0}'
    ";

    /// <summary>
    /// 获得数据连接
    /// </summary>
    /// <returns></returns>
    private SqlConnection GetConnection()
    {
    return new SqlConnection(CONNECTION_STRING);
    }
    /// <summary>
    /// 释放连接
    /// </summary>
    /// <param name="con"></param>
    private void ReleaseConnection(SqlConnection con)
    {
    if (con != null)
    {
    if (con.State == ConnectionState.Open)
    {
    con.Close();
    }
    }
    }

    /// <summary>
    ///
    /// </summary>
    /// <param name="tableName"></param>
    public DataTable GetTableSchema(string tableName)
    {
    DataTable dt;
    using (SqlConnection con = GetConnection())
    {
    con.Open();

    SqlCommand cmd = con.CreateCommand();
    cmd.CommandText = string.Format(SELECT_SCHEMA_BY_TABLE_NAME,tableName);
    cmd.CommandType = CommandType.Text;

    SqlDataAdapter adapter = new SqlDataAdapter(cmd);
    DataSet ds = new DataSet();
    adapter.Fill(ds);
    dt = ds.Tables[0];
    }

    return dt;
    }
    /// <summary>
    ///
    /// </summary>
    public void Generate()
    {
    DataTable table = GetTableSchema(PERSONINFO_TABLE_NAME);

    if (table != null && table.Rows.Count > 0)
    {
    foreach (DataRow row in table.Rows)
    {
    Console.WriteLine("public class {0}", row["TableName"]);
    Console.WriteLine("public {0} {1}", TransFromSqlType(row["DataType"].ToString()), row["ColumnName"]);
    }
    }
    }
    /// <summary>
    /// SQL
    /// </summary>
    /// <param name="type"></param>
    /// <returns></returns>
    public string TransFromSqlType(string type)
    {
    if (string.IsNullOrEmpty(type))
    {
    return string.Empty;
    }

    if (string.Equals(type, "int", StringComparison.OrdinalIgnoreCase))
    {
    return "int";
    }
    else if (string.Equals(type, "nvarchar", StringComparison.OrdinalIgnoreCase))
    {
    return "string";
    }

    return "string";
    }

    }
    #>


    4、生成代码并调试修改。

      其实转过来时,出现错误的几率已经很少,比较难调的就是某些组件的引用。

    5、结果,T4模板生成的代码

    using System;

    namespace Model
    {
    public class PersonInfo
    {
    public int ID { get; set; }

    public string NAME { get; set; }

    public string Company { get; set; }

    public string Job { get; set; }

    }
    }

    四、源码地址

    源码地址,点击下载


    如果觉的对您有帮助,请推荐!


  • 相关阅读:
    .net开发环境的选择
    html头部的一些信息
    SQLHelper类
    C#实现文件下载
    js类
    Winform小知识点
    emacs 代码缩进
    自己喜欢的shell终端配置
    time_wait过多的优化
    Emacs 电子邮件组件RMAIL
  • 原文地址:https://www.cnblogs.com/yank/p/2356049.html
Copyright © 2020-2023  润新知