基于数据库的vs2019的T4模版代码生成器基于sqlserver数据库

Posted 谢文宇

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于数据库的vs2019的T4模版代码生成器基于sqlserver数据库相关的知识,希望对你有一定的参考价值。

总体介绍

参考文档:

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.FrameWorkT4 

2、在该类库下,新建文件夹 Xwy.Core.FrameWorkT4.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;
            }
        }
    }
}#>

5 DbHelper.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;
            }
        }
    }
}#>

6 模板文件Entity.tt

//如果要获取主机信息,记得把 hostspecific 设置成true
<#@ template debug="false" hostspecific="True" language="C#" #>
<#@ output extension=".cs" #>

//导入命名空间组件
<#@ assembly name="System.Data" #>
<#@ assembly name="System.xml" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Data.SqlClient" #>
<#@ import namespace="System.Data" #>
<#@ assembly name="System.Core.dll" #>
<#@ assembly name="System.Data.DataSetExtensions.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Xml" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.IO" #>

//引入我们的公共模板文件
<#@ include file="$(ProjectDir)DbHelper.ttinclude"  #>
<#@ include file="$(ProjectDir)ModelAuto.ttinclude"    #>

//定义我们的输出文件夹
<# 
    var OutputPath1 = Path.GetDirectoryName(Host.TemplateFile)+"\\\\work";
    if (!Directory.Exists(OutputPath1))
    {
        Directory.CreateDirectory(OutputPath1);
    }
     var manager = new Manager(Host, GenerationEnvironment, true) { OutputPath = OutputPath1 }; 
#>


//--------------------------------------------------------------------
//     此代码由T4模板自动生成
//    老张的哲学 生成时间 <#=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")#> 
//     注意更新后会改变相应代码。
//--------------------------------------------------------------------
<# 
    var tableName=config.TableName;//获取config配置中的表名,为单一生产使用
 #>
<# 
if(tableName!=""){//如果表名有值,表示是生成单一文件
    #>  
//引用命名空间
using System;
namespace Blog.Core.FrameWork.Entity
{    
    /// <summary>
    /// <#=tableName#>
    /// </summary>    
    public class <#=tableName#>//可以在这里加上基类等
    {
    //将全部字段遍历出来
<# foreach(DbColumn column in DbHelper.GetDbColumns(config.ConnectionString, config.DbDatabase, config.TableName)){#>
      public <#= column.CSharpType#><# if(column.CommonType.IsValueType && column.IsNullable){#>?<#}#> <#=column.ColumnName#> { get; set; }
<#}#> 
    }
}
//如果为空,表示要将整个数据库都生成出来
<# 
    } else{ 

    #>
    //连接数据库,打开 connect 连接
<# 
    SqlConnection conn = new SqlConnection(config.ConnectionString); 
    conn.Open(); 
    System.Data.DataTable schema = conn.GetSchema("TABLES"); 
 #>
 //遍历全部数据库表
<# 
    foreach(System.Data.DataRow row in schema.Rows) 
    {  #>   

    //开始启动block块,参数是实体类文件名
    <# 
        manager.StartBlock(row["TABLE_NAME"]+".cs");
     #>
using System;
namespace Blog.Core.FrameWork.Entity
{    
    /// <summary>
    /// <#=tableName#>
    /// </summary>    
    public class <#=row["TABLE_NAME"].ToString()#>//可以在这里加上基类等
    {
    //将该表下的字段都遍历出来,可以自定义获取数据描述等信息
<# foreach(DbColumn column in DbHelper.GetDbColumns(config.ConnectionString, config.DbDatabase, row["TABLE_NAME"].ToString() )){ #>

      public <#= column.CSharpType#><# if(column.CommonType.IsValueType && column.IsNullable){#>?<#}#> <#=column.ColumnName #> { get; set; }
<#}#> 

    }
}
    <# 
        manager.EndBlock(); 
        } 
        manager.Process(true);
    }
    #>

 

以上是关于基于数据库的vs2019的T4模版代码生成器基于sqlserver数据库的主要内容,如果未能解决你的问题,请参考以下文章

T4 模板

T4语法快速入门

利用T4模版生成EF实体

如何使T4文本模板数据库驱动

T4模版引擎之基础入门

基于模版文件复制替换的abpcore代码生成器