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; }
}
}
后续将补上:把生成的模板添加到项目中进行生成代码,包含:仓储,服务,控制器,校验等