天天看点

Net 中 T4 生成模板

作者:简单d猫

1、什么是T4

T4 代表文本模板转换工具包。

简而言之,“一个在 Visual Studio 中自动生成文本文件的系统”。例如,“从表定义文件自动生成实体类”很方便。

2、项目准备

a、指定创建项目的目录

cd /home           

b、安装dotnet-t4

dotnet new tool-manifest
dotnet tool install dotnet-t4           

3、创建项目

dotnet new console           

a、安装依赖包

模板文件生成的程序代码依赖这个包 Mono.TextTemplating

dotnet add package Mono.TextTemplating           

b、表/属性 类定义

TableInfo和ColumnInfo 定义

public class Table
	{
		public List<Column> Columns;
		public string Name;
		public string Schema;
		public bool IsView;
		public string CleanName;
		public string ClassName;
		public string SequenceName;
		public bool Ignore;

		public Column PK
		{
			get
			{
				return this.Columns.FirstOrDefault(x => x.IsPK);
			}
		}

		public Column GetColumn(string columnName)
		{
			return Columns.Single(x => string.Compare(x.Name, columnName, true) == 0);
		}

		public Column this[string columnName]
		{
			get
			{
				return GetColumn(columnName);
			}
		}

	}

//Column
	public class Column
	{
		public Column()
		{
			Remark = string.Empty;
		}
		public string Name;
		public string PropertyName;
		public string PropertyType;
		public bool IsPK;
		public bool IsNullable;
		public bool IsAutoIncrement;
		public bool Ignore;
		public string Remark;
	}
           

c、预编译项目文件.csproj 添加

//t4模板 和 生成的文件定义
<ItemGroup>
	<TextTemplate Include="**\*.tt" />
	<Generated Include="**\T4\*.Generated.cs" />
</ItemGroup>           

d、定义构建前要执行的过程

添加dotnet t4以在 build 之前调用命令

<Target Name="TextTemplateTransform" BeforeTargets="BeforeBuild">
<Exec WorkingDirectory="$(ProjectDir)" Command="dotnet t4 %(TextTemplate.Identity) -c $(RootNameSpace).T4.%(TextTemplate.Filename) -o T4\%(TextTemplate.Filename).Generated.cs" />
  </Target>           

e、构建后清理处理

<Target Name="TextTemplateClean" AfterTargets="Clean">
	<Delete Files="@(Generated)" />
</Target>           

4、创建模板文件

a、模板生成之前默认实现

public interface ITextTemplate
{
      string TransformText() => string.Empty;
}           

b、创建模板部分类

比如:

public partial class TableEntityTemplate : ITextTemplate
{
        /// <summary>
        /// Assigns Databases Column Type Name to .NET Type Name.
        /// </summary>
        private readonly Dictionary<string, string> _typeDictionary;

        /// <summary>
        /// Entity's Namespace.
        /// </summary>
        public string NameSpace { get; }

        /// <summary>
        /// Table Data.
        /// </summary>
        public Table Table { get; }

       /// <summary>
       /// 创建
       /// </summary>
       /// <param name="typeDictionary"></param>
       /// <param name="nameSpace"></param>
       /// <param name="table"></param>
        public TableEntityTemplate(Dictionary<string, string> typeDictionary, string nameSpace, Table table)
            => (_typeDictionary, NameSpace, Table) = (typeDictionary, nameSpace, table);

       /// <summary>
       /// 获取属性类型
       /// </summary>
       /// <param name="column"></param>
       /// <returns></returns>
        public string GetColumnType(Column column)
            => _typeDictionary.TryGetValue(column.PropertyType, out string n) ? n : column.PropertyType
                + (column.IsNullable ? "" : "?");
        /// <summary>
        /// 类名
        /// </summary>
        public string ClassName => UtilityHelper.ChangeClassName(Table.Name);
        /// <summary>
        /// 属性名称
        /// </summary>
        /// <param name="propertyName"></param>
        /// <returns></returns>
        public string ChangePropertyName(string propertyName) => UtilityHelper.ChangePropertyName(propertyName);

        public string CheckNullable(Column col)
        {
            string result = "";
            if (col.IsNullable &&
                col.PropertyType != "byte[]" &&
                col.PropertyType != "string" &&
                col.PropertyType != "Microsoft.SqlServer.Types.SqlGeography" &&
                col.PropertyType != "Microsoft.SqlServer.Types.SqlGeometry"
                )
                result = "?";
            return result;
        }
}
           

c、创建T4文件

<#@ template language="C#" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="DataHelper" #>
<#@ output extension=".cs" #>

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using XXX.Core.Domain.Models.Entity;

namespace <#= NameSpace #>
{ 
   [Table("<#= Table.ClassName #>")]
   public partial class <#=ClassName#> : BaseBusinessEntity<int?>
   {
   <#
   foreach(Column col in from c in Table.Columns where !c.Ignore select c)
   {
    
        if(col.PropertyName == "id" 
        || col.PropertyName == "business_id"
        || col.PropertyName == "create_time"
        || col.PropertyName == "create_id"
        || col.PropertyName == "is_del"
        || col.PropertyName == "update_id"
        || col.PropertyName == "update_time") continue;
      
   #>
      /// <summary>
      /// <#=col.Remark.Replace("\r\n"," ")#>
      /// </summary>
     [Column("<#= col.PropertyName #>")]
      public <#=col.PropertyType #><#=CheckNullable(col)#> <#=ChangePropertyName(col.PropertyName)#> { get; set; }
   <# 
   }
   #>
   }
}           

d、主程序创建实例

namespace ConsoleApp1
{
    class Program
    {
        
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");

            var typeDef = new Dictionary<string, string>()
            {
                { "integer", "int" },
                { "varchar", "string" },
                { "date", "DateTime" },
            };

            var table = new Table
            {
                ClassName = "User",
                Name = "user",
                Columns = new List<Column>
                {
                    new Column
                    {
                        IsPK = false,
                        Name ="age",
                        IsNullable = true,
                        PropertyName = "age",
                        PropertyType ="int",
                        Remark = "年龄"
                    },
                    new Column
                    {
                        IsPK = false,
                        Name = "name",
                        IsNullable = true,
                        PropertyType = "string",
                        PropertyName = "name",
                        Remark = "名称"
                    }
                },
                
            };

            ITextTemplate template = new TableEntityTemplate(typeDef, "MyNameSpace", table);
            var content = template.TransformText();
            Console.WriteLine(content);
        }
    }
}           
> dotnet build
//生成TableEntityTemplate.Generated.cs 文件
> dotnet run
//生成 User 实体
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using XXX.Core.Domain.Models.Entity;

namespace MyNameSpace
{
   [Table("User")]
   public partial class User : BaseBusinessEntity<int?>
   {
         /// <summary>
      /// 年龄
      /// </summary>
     [Column("age")]
      public int? Age { get; set; }
         /// <summary>
      /// 名称
      /// </summary>
     [Column("name")]
      public string Name { get; set; }
      }
}           

后续将补上:把生成的模板添加到项目中进行生成代码,包含:仓储,服务,控制器,校验等