zoukankan      html  css  js  c++  java
  • 基于数据库的vs2019的T4模版代码生成器(二)基于mysql数据库

    总体介绍

    参考文档:

    https://www.cnblogs.com/laozhang-is-phi/p/9757999.html

    只想用 ADO.NET 搭建多层框架,动软代码生成器是一个不错的选择。

    T4 (Text Template Transformation Toolkit) 是微软官方在 VisualStudio 2008+ 中开始使用的代码生成引擎。在 Visual Studio 中,“T4 文本模板”是由一些文本块和控制逻辑组成的混合模板,它可以生成文本文件。 在 Visual C# 或 Visual Basic 中,控制逻辑编写为程序代码的片段。生成的文件可以是任何类型的文本,例如网页、资源文件或任何语言的程序源代码。现在的VS中只要与代码生成相关的场景基本上都能找T4的身影,比如MVC的视图模板,Entity Framwork的DataContext模板等等。

     这里就不具体讲解 T4 语法了,大家可以自行学习,其实很简单,主要还是 C# 代码,下边你看过之后就能懂了,咱们首先先实现之前留下的一个伏笔 —— 将我们的数据库表利用T4 模板生成实体类,也就是 DbFirst。

    1 首先在我们的项目中,新建一个类库 Xwy.Core.FrameWorkT4Mysql 

    2 在该类库下,新建文件夹 Xwy.Core.FrameWorkT4Mysql.Entity,用于单独存放我们的模板以及生成的实体类文件

    3 ModelAuto.ttinclude 文本文件代码

    //引入命名空间
    <#@ assembly name="System.Core"#>
    <#@ assembly name="EnvDTE"#>
    <#@ import namespace="System.Collections.Generic"#>
    <#@ import namespace="System.IO"#>
    <#@ import namespace="System.Text"#>
    <#@ import namespace="Microsoft.VisualStudio.TextTemplating"#>
    
    <#+
    //定义管理者 manager 实体类
    class Manager
    {
        //定义一个 block 块,主要是应用在批量生产中
        public struct Block {
            public String Name;
            public int Start, Length;
        }
    
        public List<Block> blocks = new List<Block>();
        public Block currentBlock;
        public Block footerBlock = new Block();
        public Block headerBlock = new Block();
        public ITextTemplatingEngineHost host;
        public ManagementStrategy strategy;
        public StringBuilder template;
        public String OutputPath { get; set; }
        //构造函数,包含 host主机,模板,输出路径,创建管理策略
        public Manager(ITextTemplatingEngineHost host, StringBuilder template, bool commonHeader) {
            this.host = host;
            this.template = template;
            OutputPath = String.Empty;
            strategy = ManagementStrategy.Create(host);
        }
        //开辟一个 block 块
        public void StartBlock(String name) {
            currentBlock = new Block { Name = name, Start = template.Length };
        }
    
        public void StartFooter() {
            footerBlock.Start = template.Length;
        }
    
        public void EndFooter() {
            footerBlock.Length = template.Length - footerBlock.Start;
        }
    
        public void StartHeader() {
            headerBlock.Start = template.Length;
        }
    
        public void EndHeader() {
            headerBlock.Length = template.Length - headerBlock.Start;
        }    
    
        public void EndBlock() {
            currentBlock.Length = template.Length - currentBlock.Start;
            blocks.Add(currentBlock);
        }
        //定义进程,用来将所有的 blocks 块执行出来
        public void Process(bool split) {
            String header = template.ToString(headerBlock.Start, headerBlock.Length);
            String footer = template.ToString(footerBlock.Start, footerBlock.Length);
            blocks.Reverse();
            foreach(Block block in blocks) {//遍历
                //输出文件
                String fileName = Path.Combine(OutputPath, block.Name);
                if (split) {
                    String content = header + template.ToString(block.Start, block.Length) + footer;
                    strategy.CreateFile(fileName, content);
                    template.Remove(block.Start, block.Length);
                } else {
                    strategy.DeleteFile(fileName);
                }
            }
        }
    }
    //定义管理策略类
    class ManagementStrategy
    {
        internal static ManagementStrategy Create(ITextTemplatingEngineHost host) {
            return (host is IServiceProvider) ? new VSManagementStrategy(host) : new ManagementStrategy(host);
        }
    
        internal ManagementStrategy(ITextTemplatingEngineHost host) { }
    
        internal virtual void CreateFile(String fileName, String content) {
            File.WriteAllText(fileName, content);
        }
    
        internal virtual void DeleteFile(String fileName) {
            if (File.Exists(fileName))
                File.Delete(fileName);
        }
    }
    
    class VSManagementStrategy : ManagementStrategy
    {
        private EnvDTE.ProjectItem templateProjectItem;
    
        internal VSManagementStrategy(ITextTemplatingEngineHost host) : base(host) {
            IServiceProvider hostServiceProvider = (IServiceProvider)host;
            if (hostServiceProvider == null)
                throw new ArgumentNullException("Could not obtain hostServiceProvider");
    
            EnvDTE.DTE dte = (EnvDTE.DTE)hostServiceProvider.GetService(typeof(EnvDTE.DTE));
            if (dte == null)
                throw new ArgumentNullException("Could not obtain DTE from host");
    
            templateProjectItem = dte.Solution.FindProjectItem(host.TemplateFile);
        }
        //创建文件
        internal override void CreateFile(String fileName, String content) {
            base.CreateFile(fileName, content);
            ((EventHandler)delegate { templateProjectItem.ProjectItems.AddFromFile(fileName); }).BeginInvoke(null, null, null, null);
        }
        //删除文件
        internal override void DeleteFile(String fileName) {
            ((EventHandler)delegate { FindAndDeleteFile(fileName); }).BeginInvoke(null, null, null, null);
        }
        //根据文件名删除文件
        private void FindAndDeleteFile(String fileName) {
            foreach(EnvDTE.ProjectItem projectItem in templateProjectItem.ProjectItems) {
                if (projectItem.get_FileNames(0) == fileName) {
                    projectItem.Delete();
                    return;
                }
            }
        }
    }#>

    4 MySqlHelper.ttinclude文本文件

    <#+
    public class EntityHelper
        {
            public static List<Entity> GetEntities(string connectionString, List<string> databases)
            {
                var list = new List<Entity>();
                var conn = new MySqlConnection(connectionString);
                try
                {
                    conn.Open();
                    var dbs = string.Join("','", databases.ToArray());
                    var cmd = string.Format(@"SELECT `information_schema`.`COLUMNS`.`TABLE_SCHEMA`
                                                        ,`information_schema`.`COLUMNS`.`TABLE_NAME`
                                                        ,`information_schema`.`COLUMNS`.`COLUMN_NAME`
                                                        ,`information_schema`.`COLUMNS`.`DATA_TYPE`
                                                        ,`information_schema`.`COLUMNS`.`COLUMN_COMMENT`
                                                    FROM `information_schema`.`COLUMNS`
                                                    WHERE `information_schema`.`COLUMNS`.`TABLE_SCHEMA` IN ('{0}') ", dbs);
                    using (var reader = MySqlHelper.ExecuteReader(conn, cmd))
                    {
                        while (reader.Read())
                        {
                            var db = reader["TABLE_SCHEMA"].ToString();
                            var table = reader["TABLE_NAME"].ToString();
                            var column = reader["COLUMN_NAME"].ToString();
                            var type =  reader["DATA_TYPE"].ToString();
                            var comment = reader["COLUMN_COMMENT"].ToString();
                            var entity = list.FirstOrDefault(x => x.EntityName == table);
                            if(entity == null)
                            {
                                entity = new Entity(table);
                                entity.Fields.Add(new Field
                                {
                                    Name = column,
                                    Type = GetCLRType(type),
                                    Comment = comment
                                });
                               
                                list.Add(entity);
                            }
                            else
                            {
                                entity.Fields.Add(new Field
                                {
                                    Name = column,
                                    Type = GetCLRType(type),
                                    Comment = comment
                                });
                            }
                        }
                    }
                }
                finally
                {
                    conn.Close();
                }
    
                return list;
            }
    
            public static string GetCLRType(string dbType)
            {
                switch(dbType)
                {
                    case "tinyint":
                    case "smallint":
                    case "mediumint":
                    case "int":
                    case "integer":
                        return "int";
                    case "double":
                        return "double";
                    case "float":
                        return "float";
                    case "decimal":
                        return "decimal";
                    case "numeric":
                    case "real":
                        return "decimal";
                    case "bit":
                        return "bool";
                    case "date":
                    case "time":
                    case "year":
                    case "datetime":
                    case "timestamp":
                        return "DateTime";
                    case "tinyblob":
                    case "blob":
                    case "mediumblob":
                    case "longblog":
                    case "binary":
                    case "varbinary":
                        return "byte[]";
                    case "char":
                    case "varchar":                   
                    case "tinytext":
                    case "text":
                    case "mediumtext":
                    case "longtext":
                        return "string";
                    case "point":
                    case "linestring":
                    case "polygon":
                    case "geometry":
                    case "multipoint":
                    case "multilinestring":
                    case "multipolygon":
                    case "geometrycollection":
                    case "enum":
                    case "set":
                    default:
                        return dbType;
                }
            }
        }
    
        public class Entity
        {
            public Entity()
            {
                this.Fields = new List<Field>();
            }
    
            public Entity(string name)
                : this()
            {
                this.EntityName = name;
            }
    
            public string EntityName { get;set; }
            public List<Field> Fields { get;set; }
            public string PascalEntityName
            {
                get{
                    return    CommonConver.ToPascalCase(this.EntityName);
                }
            }
            public string CamelEntityName
            {
                get{
                    return    CommonConver.ToCamelCase(this.EntityName);
                }
            }
        }
    
        public class Field
        {
            public string Name { get;set; }
            public string Type { get;set; }
            public string Comment { get;set; }
        }
        public class CommonConver
        {
            public static string ToPascalCase(string tableName)
            {
                string upperTableName = tableName.Substring(0, 1).ToUpper() + tableName.Substring(1, tableName.Length - 1);
                return upperTableName;
            }    
            public static string ToCamelCase(string tableName)
            {
                string lowerTableName = tableName.Substring(0, 1).ToLower() + tableName.Substring(1, tableName.Length - 1);
                return lowerTableName;
            }    
        }
    
    class config
        {
            
            public static readonly string ConnectionString = "Database=openauth;Data Source=127.0.0.1;User Id=root;Password=;pooling=false;CharSet=utf8;port=3306";
            public static readonly string DbDatabase = "";
            public static readonly string TableName = "";
            public static readonly string ModelNameSpace = "App.Entities";
            public static readonly string IRepositoryNameSpace = "App.IRepository";
            public static readonly string RepositoryNameSpace = "App.Repository";
            public static readonly string IServicesNameSpace = "App.IServices";
            public static readonly string ServicesNameSpace = "App.Services";
        }#>

    5 模板文件Entity.tt

    <#@ template debug="false" hostspecific="True" language="C#" #>
    <#@ output extension=".cs" #>
    
    <#@ assembly name="System.Core.dll" #>
    <#@ assembly name="System.Data.dll" #>
    <#@ assembly name="System.Data.DataSetExtensions.dll" #>
    <#@ assembly name="System.Xml.dll" #>
    <#@ assembly name="C:Userschuanchuan.nugetpackagesmysql.data8.0.14lib
    et452MySql.Data.dll" #>
    <#@ import namespace="System" #>
    <#@ import namespace="System.Xml" #>
    <#@ import namespace="System.Linq" #>
    <#@ import namespace="System.Data" #>
    <#@ import namespace="System.Data.SqlClient" #>
    <#@ import namespace="System.Collections.Generic" #>
    <#@ import namespace="System.IO" #>
    <#@ import namespace="MySql.Data.MySqlClient" #>
    
    <#@ include file="$(ProjectDir)MySqlHelper.ttinclude"  #>
    <#@ include file="$(ProjectDir)ModelAuto.ttinclude"    #>
    
    <#
        // 是否是WCF服务模型
        //C:Usersyouga.nugetpackagesmysql.data8.0.14lib
    et452
        bool serviceModel = false;
       
        // 数据库连接
        var connectionString = @"Data Source=127.0.0.1;User Id=root;Password=;pooling=false;CharSet=utf8;port=3306";
    
        // 需要解析的数据库
        var database = new List<string> { "openauthdb" };
    
        // 文件版权信息
        var copyright = DateTime.Now.Year + " xxxx Enterprises All Rights Reserved";
        var version = Environment.Version;
        var author = "auto generated by T4";
    
         var OutputPath1 = Path.GetDirectoryName(Host.TemplateFile)+"\work";
        if (!Directory.Exists(OutputPath1))
        {
            Directory.CreateDirectory(OutputPath1);
        }
    
        var manager = new Manager(Host, GenerationEnvironment, true) { OutputPath = OutputPath1 };
        var entities = EntityHelper.GetEntities(connectionString, database);
    
        foreach(Entity entity in entities)
        {
            manager.StartBlock(entity.EntityName + ".cs");
    #>
    //-----------------------------------------------------------------------
    // <copyright file=" <#= entity.EntityName #>.cs" company="xxxx Enterprises">
    // * Copyright (C) <#= copyright #>
    // * version : <#= version #>
    // * author  : <#= author #>
    // * FileName: <#= entity.EntityName #>.cs
    // * history : Created by T4 <#= DateTime.Now #>
    // </copyright>
    //-----------------------------------------------------------------------
    using System;
    <#    if(serviceModel)
        {
    #>
    using System.Runtime.Serialization;
    <#
        }
    #>
    
    namespace <#=config.ModelNameSpace#>
    {
        /// <summary>
        /// <#= entity.EntityName #> Entity Model
        /// </summary>   
        [Serializable]
    <#    if(serviceModel)
        {
    #>
        [DataContract]
    <#
        }
    #>
        public class <#= entity.EntityName #>
        {
    <#
            for(int i = 0; i < entity.Fields.Count; i++)
            {
                if(i ==0){
    #>        /// <summary>
            /// <#= entity.Fields[i].Comment #>
            /// </summary>
    <#    if(serviceModel)
        {
    #>
            [DataMember]
    <#
        }
    #>
            public <#= entity.Fields[i].Type #> <#= entity.Fields[i].Name #> { get; set; }
    <#
                }
                else{
    #>   
            /// <summary>
            /// <#= entity.Fields[i].Comment #>
            /// </summary>
    <#    if(serviceModel)
        {
    #>
            [DataMember]
    <#
        }
    #>
            public <#= entity.Fields[i].Type #> <#= entity.Fields[i].Name #> { get; set; }
    <#            }
            }
    #>
        }
    }
    <#       
            manager.EndBlock();
        }
    
        manager.Process(true);
    #>

     注意事项:

    1、<#@ assembly name="C:Usersyouga.nugetpackagesmysql.data8.0.14lib et452MySql.Data.dll" #>  修改为你的引用;
    2、MySqlHelper.ttinclude 修改ConnectionString变量;
    3、App.Entities.tt 修改connectionString变量;
    4、可以根据自己的需求修改T4模板;
    5、生成的类名都是小写,可否转化为帕斯卡命名规范(待解决); 

    6、如果MySQL要生成大写的话,需要在my.ini中添加 lower_case_table_names=2,让mysql区分大小写,生成出来的就跟所设置的表名,字段名一样了,默认mysql在windows下不区分大小写。

    <#@ template debug="false" hostspecific="True" language="C#" #><#@ output extension=".cs" #>
    <#@ assembly name="System.Core.dll" #><#@ assembly name="System.Data.dll" #><#@ assembly name="System.Data.DataSetExtensions.dll" #><#@ assembly name="System.Xml.dll" #><#@ assembly name="C:Userschuanchuan.nugetpackagesmysql.data8.0.14lib et452MySql.Data.dll" #><#@ import namespace="System" #><#@ import namespace="System.Xml" #><#@ import namespace="System.Linq" #><#@ import namespace="System.Data" #><#@ import namespace="System.Data.SqlClient" #><#@ import namespace="System.Collections.Generic" #><#@ import namespace="System.IO" #><#@ import namespace="MySql.Data.MySqlClient" #>
    <#@ include file="$(ProjectDir)MySqlHelper.ttinclude"  #><#@ include file="$(ProjectDir)ModelAuto.ttinclude"#>
    <#    // 是否是WCF服务模型//C:Usersyouga.nugetpackagesmysql.data8.0.14lib et452    bool serviceModel = false;       // 数据库连接    var connectionString = @"Data Source=127.0.0.1;User Id=root;Password=;pooling=false;CharSet=utf8;port=3306";
        // 需要解析的数据库    var database = new List<string> { "openauthdb" };
        // 文件版权信息    var copyright = DateTime.Now.Year + " xxxx Enterprises All Rights Reserved";    var version = Environment.Version;    var author = "auto generated by T4";
    var OutputPath1 = Path.GetDirectoryName(Host.TemplateFile)+"\work";if (!Directory.Exists(OutputPath1)){Directory.CreateDirectory(OutputPath1);}
        var manager = new Manager(Host, GenerationEnvironment, true) { OutputPath = OutputPath1 };    var entities = EntityHelper.GetEntities(connectionString, database);
        foreach(Entity entity in entities)    {        manager.StartBlock(entity.EntityName + ".cs");#>//-----------------------------------------------------------------------// <copyright file=" <#= entity.EntityName #>.cs" company="xxxx Enterprises">// * Copyright (C) <#= copyright #>// * version : <#= version #>// * author  : <#= author #>// * FileName: <#= entity.EntityName #>.cs// * history : Created by T4 <#= DateTime.Now #>// </copyright>//-----------------------------------------------------------------------using System;<#    if(serviceModel)    {#>using System.Runtime.Serialization;<#    }#>
    namespace <#=config.ModelNameSpace#>{    /// <summary>    /// <#= entity.EntityName #> Entity Model    /// </summary>       [Serializable]<#    if(serviceModel)    {#>    [DataContract]<#    }#>    public class <#= entity.EntityName #>    {<#        for(int i = 0; i < entity.Fields.Count; i++)        {            if(i ==0){#>        /// <summary>        /// <#= entity.Fields[i].Comment #>        /// </summary><#    if(serviceModel)    {#>        [DataMember]<#    }#>        public <#= entity.Fields[i].Type #> <#= entity.Fields[i].Name #> { get; set; }<#            }            else{#>           /// <summary>        /// <#= entity.Fields[i].Comment #>        /// </summary><#    if(serviceModel)    {#>        [DataMember]<#    }#>        public <#= entity.Fields[i].Type #> <#= entity.Fields[i].Name #> { get; set; }<#            }        }#>    }}<#               manager.EndBlock();    }
        manager.Process(true);#>

  • 相关阅读:
    浅读《构建之法》随笔
    个人学期总结
    201571030305/201571030306《小学生四则运算需求分析结对报告》
    小学生四则运算结对项目
    小学生四则运算
    读《构建之法》提出的问题
    个人学期总结
    实验四 小学生四则运算需求分析结对报告
    四则运算结对项目
    四则运算 201571030317
  • 原文地址:https://www.cnblogs.com/xiewenyu/p/13111772.html
Copyright © 2011-2022 走看看