使用T4模板根据数据库生成model层

前言

学习EF时接触到T4模板,感觉到了它的强大。既然EF的edmx文件下的tt文件可以生成model层的cs文件,那么我们也可以直接用T4模板生成model层喽。当然T4可以做更多事,不过今日我们只让它做这一件事。
本文主要参考以下文章:
MVC —- Manager.ttinclude内容
Multiple Output Files using T4


主要内容

T4模板介绍

T4,即4个T开头的英文字母组合:Text Template Transformation Toolkit。简单来说就是自定义规则代码生成文件。T4模板因其扩展名为“.tt”又叫做tt模板。
T4模板里面可以在<##>里面写入代码而达到类似aspx页面动态输出效果。
T4内的一些类和方法我们不再深究。

添加生成文件Manager.ttinclude

T4内Damien Guard的扩展可以方便的生成多个文件。这里借用上面参考文章的方法,将生成多个文件的扩展封装成一个单独的文件,在T4内生成多个文件时只要引用这个文件并且使用这个文件内的方法就行了。

首先,新建文本文件,保存以下代码为一个模板文件(例如保存文件名为Manager.ttinclude)。

<#@ assembly name="System.Core"#>
<#@ assembly name="System.Data.Linq"#>
<#@ assembly name="EnvDTE"#>
<#@ assembly name="System.Xml"#>
<#@ assembly name="System.Xml.Linq"#>
<#@ import namespace="System"#>
<#@ import namespace="System.CodeDom"#>
<#@ import namespace="System.CodeDom.Compiler"#>
<#@ import namespace="System.Collections.Generic"#>
<#@ import namespace="System.Data.Linq"#>
<#@ import namespace="System.Data.Linq.Mapping"#>
<#@ import namespace="System.IO"#>
<#@ import namespace="System.Linq"#>
<#@ import namespace="System.Reflection"#>
<#@ import namespace="System.Text"#>
<#@ import namespace="System.Xml.Linq"#>
<#@ import namespace="Microsoft.VisualStudio.TextTemplating"#>
<#+

// Manager class records the various blocks so it can split them up
class Manager {
    private class Block {
        public String Name;
        public int Start, Length;
    }

    private Block currentBlock;
    private List<Block> files = new List<Block>();
    private Block footer = new Block();
    private Block header = new Block();
    private ITextTemplatingEngineHost host;
    private StringBuilder template;
    protected List<String> generatedFileNames = new List<String>();

    public static Manager Create(ITextTemplatingEngineHost host, StringBuilder template) {
        return (host is IServiceProvider) ? new VSManager(host, template) : new Manager(host, template);
    }

    public void StartNewFile(String name) {
        if (name == null)
            throw new ArgumentNullException("name");
        CurrentBlock = new Block { Name = name };
    }

    public void StartFooter() {
        CurrentBlock = footer;
    }

    public void StartHeader() {
        CurrentBlock = header;
    }

    public void EndBlock() {
        if (CurrentBlock == null)
            return;
        CurrentBlock.Length = template.Length - CurrentBlock.Start;
        if (CurrentBlock != header && CurrentBlock != footer)
            files.Add(CurrentBlock);
        currentBlock = null;
    }

    public virtual void Process(bool split) {
        if (split) {
            EndBlock();
            String headerText = template.ToString(header.Start, header.Length);
            String footerText = template.ToString(footer.Start, footer.Length);
            String outputPath = Path.GetDirectoryName(host.TemplateFile);
            files.Reverse();
            foreach(Block block in files) {
                String fileName = Path.Combine(outputPath, block.Name);
                String content = headerText + template.ToString(block.Start, block.Length) + footerText;
                generatedFileNames.Add(fileName);
                CreateFile(fileName, content);
                template.Remove(block.Start, block.Length);
            }
        }
    }

    protected virtual void CreateFile(String fileName, String content) {
        if (IsFileContentDifferent(fileName, content))
            File.WriteAllText(fileName, content);
    }

    public virtual String GetCustomToolNamespace(String fileName) {
        return null;
    }

    public virtual String DefaultProjectNamespace {
        get { return null; }
    }

    protected bool IsFileContentDifferent(String fileName, String newContent) {
        return !(File.Exists(fileName) && File.ReadAllText(fileName) == newContent);
    }

    private Manager(ITextTemplatingEngineHost host, StringBuilder template) {
        this.host = host;
        this.template = template;
    }

    private Block CurrentBlock {
        get { return currentBlock; }
        set {
            if (CurrentBlock != null)
                EndBlock();
            if (value != null)
                value.Start = template.Length;
            currentBlock = value;
        }
    }

    private class VSManager: Manager {
        private EnvDTE.ProjectItem templateProjectItem;
        private EnvDTE.DTE dte;
        private Action<String> checkOutAction;
        private Action<IEnumerable<String>> projectSyncAction;

        public override String DefaultProjectNamespace {
            get {
                return templateProjectItem.ContainingProject.Properties.Item("DefaultNamespace").Value.ToString();
            }
        }

        public override String GetCustomToolNamespace(string fileName) {
            return dte.Solution.FindProjectItem(fileName).Properties.Item("CustomToolNamespace").Value.ToString();
        }

        public override void Process(bool split) {
            if (templateProjectItem.ProjectItems == null)
                return;
            base.Process(split);
            projectSyncAction.EndInvoke(projectSyncAction.BeginInvoke(generatedFileNames, null, null));
        }

        protected override void CreateFile(String fileName, String content) {
            if (IsFileContentDifferent(fileName, content)) {
                CheckoutFileIfRequired(fileName);
                File.WriteAllText(fileName, content);
            }
        }

        internal VSManager(ITextTemplatingEngineHost host, StringBuilder template)
            : base(host, template) {
            var hostServiceProvider = (IServiceProvider) host;
            if (hostServiceProvider == null)
                throw new ArgumentNullException("Could not obtain IServiceProvider");
            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);
            checkOutAction = (String fileName) => dte.SourceControl.CheckOutItem(fileName);
            projectSyncAction = (IEnumerable<String> keepFileNames) => ProjectSync(templateProjectItem, keepFileNames);
        }

        private static void ProjectSync(EnvDTE.ProjectItem templateProjectItem, IEnumerable<String> keepFileNames) {
            var keepFileNameSet = new HashSet<String>(keepFileNames);
            var projectFiles = new Dictionary<String, EnvDTE.ProjectItem>();
            var originalFilePrefix = Path.GetFileNameWithoutExtension(templateProjectItem.get_FileNames(0)) + ".";
            foreach(EnvDTE.ProjectItem projectItem in templateProjectItem.ProjectItems)
                projectFiles.Add(projectItem.get_FileNames(0), projectItem);

            // Remove unused items from the project
            foreach(var pair in projectFiles)
                if (!keepFileNames.Contains(pair.Key) && !(Path.GetFileNameWithoutExtension(pair.Key) + ".").StartsWith(originalFilePrefix))
                    pair.Value.Delete();

            // Add missing files to the project
            foreach(String fileName in keepFileNameSet)
                if (!projectFiles.ContainsKey(fileName))
                    templateProjectItem.ProjectItems.AddFromFile(fileName);
        }

        private void CheckoutFileIfRequired(String fileName) {
            var sc = dte.SourceControl;
            if (sc != null && sc.IsItemUnderSCC(fileName) && !sc.IsItemCheckedOut(fileName))
                checkOutAction.EndInvoke(checkOutAction.BeginInvoke(fileName, null, null));
        }
    }
} #>

T4内代码

创建T4模板,命名为DataModel。
这里写图片描述
粘贴以下代码:

<#@ template language="C#" hostspecific="True" debug="false"#>
<#@include file="Manager.ttinclude"#>
<#@ assembly name="System" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Data" #>
<#@ assembly name="System.Data.DataSetExtensions" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Data" #>
<#@ import namespace="System.Data.SqlClient" #>
<# var manager = Manager.Create(Host, GenerationEnvironment); #>
<#
  //你的当前model的命名空间
            string ModelNameSpace="T4Demo";
  //你的数据库连接字符串
            string ConnectStr = "Data Source=.;database=test;integrated Security =true;";
            SqlConnection MySqlConnection = new SqlConnection(ConnectStr);
            //此sql语句找到你指定数据库下的所有表
            string SelectYourTableNameStr = "SELECT * FROM sys.sysobjects WHERE TYPE='U'";
            SqlDataAdapter MySqlDataAdapter = new SqlDataAdapter(SelectYourTableNameStr, MySqlConnection);
            DataSet MyDataSet = new DataSet();
            MySqlDataAdapter.Fill(MyDataSet, "cacheTable");
            //得到table表
            DataTable MyDataTable = MyDataSet.Tables["cacheTable"];
            int MyDataTableRowsCount = MyDataTable.Rows.Count;
            for (int i = 0; i < MyDataTableRowsCount; i++)
            {
                //表名
                //MyDataTable.Rows[i]["name"].ToString();
                //此sql语句找到你当前表下的所有键值,属性,是否为null,长度。
                string SelectYourKeyStr = @"SELECT syscolumns.name as keyname,systypes.name as keyproperty,syscolumns.isnullable,syscolumns.length 
                                            FROM syscolumns, systypes 
                                            WHERE syscolumns.xusertype = systypes.xusertype 
                                            AND syscolumns.id = object_id('"+ MyDataTable.Rows[i]["name"].ToString() + "')";
                MySqlDataAdapter = new SqlDataAdapter(SelectYourKeyStr, MySqlConnection);
                 MyDataSet = new DataSet();
                MySqlDataAdapter.Fill(MyDataSet, "cacheTable");
                //得到key表
                DataTable MyKeyTable = MyDataSet.Tables["cacheTable"];
                //tt模板输出文件
                manager.StartNewFile(MyDataTable.Rows[i]["name"].ToString() +".cs");
#>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace <#=ModelNameSpace#>
{
    public  partial class <#=MyDataTable.Rows[i]["name"].ToString()#>
    {
<#              for (int keyi = 0; keyi < MyKeyTable.Rows.Count; keyi++)
                {
                    //key名
                    //MyKeyTable.Rows[keyi]["keyname"].ToString();
                    //属性
                    //MyKeyTable.Rows[keyi]["keyproperty"].ToString().ToLower();
                    //是否null
                    //MyKeyTable.Rows[keyi]["isnullable"].ToString();

                    //整型:tinyint   smallint     int    bigint
                    //精确型:decimal   numeric   
                    //近似型 float    real     
                    //日期类型:datetime   
                    // 特殊数据型  cursor timestamp   uniqueidentifier    
                    //货币型smallmoney    money

                    //输出的C#属性
                    string keypropertyOutput = string.Empty;


                    switch (MyKeyTable.Rows[keyi]["keyproperty"].ToString().ToLower())
                    {
                        case "smallint":
                            keypropertyOutput = "short";
                            break;
                        case "int":
                            keypropertyOutput = "int";
                            break;
                        case "bigint":
                            keypropertyOutput = "long";
                            break;
                        case "real":
                            keypropertyOutput = "float";
                            break;
                        case "float":
                            keypropertyOutput = "double";
                            break;
                        case "money":
                            keypropertyOutput = "decimal";
                            break;
                        case "datetime":
                            keypropertyOutput = "DateTime";
                            break;
                        case "uniqueidentifier":
                            keypropertyOutput = "Guid";
                            break;

                        case "bit":
                            keypropertyOutput = "bool";
                            break;
                        case "tinyint":
                            keypropertyOutput = "byte";
                            break;
                        case "image":
                            keypropertyOutput = "byte[]";
                            break;
                        case "binary":
                            keypropertyOutput = "byte[]";
                            break;
                        default:
                            keypropertyOutput = "string";
                                break;
                    }
                    //可为null且不是string(就是值类型)可以加?
                    if (MyKeyTable.Rows[keyi]["isnullable"].ToString()=="1"&& keypropertyOutput!="string")
                    {
                        if (keypropertyOutput == "byte[]")
                        {
                            keypropertyOutput = "byte?[]";
                        }
                        else
                        {
                            keypropertyOutput = keypropertyOutput + "?";
                        }
                    }
#>
                    public  <#=keypropertyOutput#>  <#=MyKeyTable.Rows[keyi]["keyname"].ToString()#>  { get; set; }
<#
                }
#>
    }
}
<#              //代码结束
                manager.EndBlock();
        MySqlConnection.Close();
            }
#>
<# manager.Process(true); #>

保存,或者点击【生成】-【转换所有T4模板】,就会在当前tt文件下生成你所需要的cs类。
这是我的数据库和表文件:
这里写图片描述
这是所生成的cs类文件:
这里写图片描述
这是UserInfo.cs文件:
这里写图片描述

总结

这样一来model层就生成成功了。以前生成model可能用动软代码生成器,现在直接在VS内部就可以生成成功。
视图或者存储过程也应该能生成,暂时没有尝试。
使用时直接修改T4代码内的命名空间字符串和数据库连接字符串就行了。
这里写图片描述

**注意:此T4模板内代码用于SqlServer数据库,其他数据库可能因为数据类型不同而生成失败,如有需要可自行修改。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: VS Code T4 模板是一种用于生成 JavaScript 代码的工具。它基于 T4(Text Template Transformation Toolkit)技术,允许开发者定义模板并在生成代码时将其应用于指定的数据。 使用 VS Code T4 模板生成 JavaScript 代码非常简单。首先,我们需要安装 "T4" 扩展插件,该插件提供了 T4 模板引擎的支持。安装完成后,我们可以创建一个新的 T4 模板文件,并在其中编写模板代码。 T4 模板使用一种特殊的标记语法,类似于 HTML 的标签。我们可以在模板中定义变量、循环、判断等逻辑,并根据需要生成相应的 JavaScript 代码。模板还可以包含外部引用的文件或库,以便在代码生成过程中使用。 一旦模板编写完成,我们可以在模板文件上右键点击,并选择 "运行 T4 模板" 选项,或使用命令面板搜索并运行相应命令。这将触发模板引擎执行,根据模板和提供的数据生成 JavaScript 代码。 T4 模板可以根据我们定义的逻辑和数据生成任意数量的 JavaScript 代码文件。这为我们提供了一种自动化生成重复代码的方式,在项目开发中可以极大地提高效率和代码质量。 总之,VS Code T4 模板提供了一种方便的方式来生成 JavaScript 代码。通过定义模板和提供相应的数据,我们可以自动生成符合需求的 JavaScript 代码,减少重复工作并提高开发效率。无论是创建新项目、添加新功能还是生成测试数据,T4 模板都能为我们提供一种强大的辅助工具。 ### 回答2: VSCode是一款功能强大的文本编辑器,它提供了许多扩展插件,其中包括T4模板生成JS。T4模板是一种用于生成代码的模板引擎,它使用C#或VB.NET编写模板代码,并通过内置的代码生成引擎将模板代码转换为最终的输出。 在VSCode中使用T4模板生成JS非常简单。首先,我们需要安装T4模板插件。可以通过在VSCode的扩展商店中搜索"T4 Template"来找到并安装这个插件。安装完成后,我们可以在VSCode的侧边栏中找到T4模板生成器的图标。 接下来,我们需要创建一个T4模板文件。可以使用`.tt`作为扩展名来命名文件,并打开该文件进行编辑。在模板文件中,我们可以使用C#或VB.NET编写代码块,并使用特定的语法来控制模板生成的过程。我们可以定义输入参数、循环结构、条件语句等,以生成不同的输出内容。 在T4模板生成JS代码的过程与生成其他类型的代码并无太大区别。我们可以在模板中定义JS变量、函数、类等,并使用T4模板提供的代码生成功能来生成相应的JS代码。 当模板文件中的代码编写完成后,我们可以保存文件并触发模板生成过程。在VSCode的命令面板中,输入"T4 Template"并选择生成模板命令,就可以将模板文件转换为对应的JS代码文件。 总结来说,使用VSCode的T4模板插件可以方便地生成JS代码。我们只需要编写模板文件,定义所需的JS代码结构和逻辑,然后由T4模板生成器自动转换为最终的JS代码文件。这样,我们可以更高效地生成大量的JS代码,并减少手工编写的工作量。 ### 回答3: VSCode是一款功能强大的代码编辑器,它支持通过T4模板生成JavaScript代码。 T4模板是一种文本生成引擎,它允许我们根据定义的模板规则生成特定的代码文件。在VSCode中使用T4模板生成JavaScript代码可以提高开发效率和代码质量。 首先,我们需要安装VSCode的T4模板插件,可以在VSCode的插件市场中搜索并安装。安装完成后,我们可以在VSCode的扩展面板中找到并启用T4模板相关功能。 接下来,在VSCode中创建一个新的文件,并将其命名为T4模板文件,通常以.tt作为文件扩展名。在T4模板文件中,我们可以使用类似于ASP.NET的标签语法来定义模板中的输入和输出。 在模板文件中,我们可以定义输入参数,例如要生成的JavaScript文件的名称和路径。然后,可以使用T4模板提供的标签和指令,通过循环、条件语句和字符串操作等方式来生成JavaScript代码。 使用T4模板生成JavaScript代码的好处是我们可以根据不同的需求和条件生成不同的代码。这样可以提高代码的可维护性和复用性。同时,T4模板还支持自定义函数和引用外部库,可以更灵活地生成JavaScript代码。 最后,我们可以通过执行模板文件来生成JavaScript代码。在VSCode中,我们可以打开T4模板文件,右键点击并选择“转换为输出文件”,这将会根据模板文件的定义生成相应的JavaScript代码文件。 总结起来,通过VSCode的T4模板插件,我们可以方便地生成JavaScript代码。通过定义模板规则和执行模板文件,我们可以根据需求快速生成高质量的JavaScript代码。这对于JavaScript开发者来说是一个非常有用的工具。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值