T4模板 根据实体模型生成具体业务代码

现有类库名为QS.Model在当前项目中 

该类库中有6个模型 5个Model都继承自DataAccess

现在我们使用这5个类生成CRUE

现在修改BLLTemplate.tt模型的代码

<#+
public class BLLTemplate : CSharpTemplate
{

	string name;
        
    public BLLTemplate(string modelName)
    {
        name = modelName;
    }

	/// <summary>
    /// 获取 生成的文件名,根据模型名定义
    /// </summary>
    public string FileName
    {
        get
        { 
            return string.Format("{0}BLL.cs", EntityName);
        }
    }

	/// <summary>
    /// 实体名称
    /// </summary>
	public string EntityName
	{
		get
		{
			return name.Replace("Model", string.Empty);
		}
	}

	public override string TransformText()
	{
		base.TransformText();
#>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Test.BLL
{
	/// <summary>
    /// 逻辑层
    /// </summary>
	public partial class TestBLL
	{
        public void Select(){
            
        }

        public void Delete(){

        }

        public void Update(){

        }

        public void Add(){

        }
	}
}
<#+
        return this.GenerationEnvironment.ToString();
	}
}
#>

具体的实现功能自己写在方法里面

修改文本文档TextTemplate2.tt代码

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ Import Namespace="System.IO" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Reflection" #>
<#@ Import Namespace="System.Collections.Generic" #>
<#@ output extension=".txt" #>
//这个必填 导入T4工具
<#@ include file="T4Toolbox.tt" #>
//这里填写bll模型的路径 当前TextTemplate2.tt目录下的Template文件夹里的BLLTemplate1.tt
<#@ include file="Template/BLLTemplate1.tt" #>


<#
    //当前TextTemplate2.tt所在的模板路径
	var currentPath = Path.GetDirectoryName(Host.TemplateFile);
    //解决方案路径
    string solutionPath = currentPath.Substring(0, currentPath.LastIndexOf("\\"));
    //项目名称
    string projectFullName = currentPath.Substring(currentPath.LastIndexOf("\\") + 1);

    //实体文件所在路径
    string modelFile = Path.Combine(solutionPath + @"\QS.Model\\bin\Debug\QS.Model.dll");
    byte[] fileData = File.ReadAllBytes(modelFile);
    Assembly assembly = Assembly.Load(fileData);

    IEnumerable<Type> modelTypes = assembly.GetTypes().Where(m => !m.IsAbstract && m.IsClass && m.BaseType != null);
    foreach (Type modelType in modelTypes)
    {
        //实例化bll模板
        BLLTemplate bll= new BLLTemplate(modelType.Name);
        string filePath= Path.Combine(currentPath,"bll", bll.FileName);
        //创建文件
        bll.RenderToFile(filePath);

    }
#>

这里用到了反射 并使用字节的方式加载 是因为在生成过程中出现过 该dll被T4模板占用 故换成此方法

然后保存或者右键TextTemplate2.tt运行自定义模板

这里可以调试T4模板在TextTemplate2.tt以打断点的方式运行调试T4模板

然后就生成成功了 

但是这里成功生成QS.Models类库下的所有类 我们只需要和数据相关的实体生成

在EF中 每个实体都有个特性TableAttribute来映射数据的表名 所以我们根据这个特性来判断是否应该生成文件

所以改动如下

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ Import Namespace="System.IO" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Reflection" #>
<#@ Import Namespace="System.Collections.Generic" #>
<#@ assembly name="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.ComponentModel.DataAnnotations.dll" #>
<#@ Import Namespace="System.ComponentModel.DataAnnotations.Schema" #>
<#@ output extension=".txt" #>
//这个必填 导入T4工具
<#@ include file="T4Toolbox.tt" #>
//这里填写bll模型的路径 当前TextTemplate2.tt目录下的Template文件夹里的BLLTemplate1.tt
<#@ include file="Template/BLLTemplate1.tt" #>


<#
    //当前TextTemplate2.tt所在的模板路径
	var currentPath = Path.GetDirectoryName(Host.TemplateFile);
    //解决方案路径
    string solutionPath = currentPath.Substring(0, currentPath.LastIndexOf("\\"));
    //项目名称
    string projectFullName = currentPath.Substring(currentPath.LastIndexOf("\\") + 1);

    //实体文件所在路径
    string modelFile = Path.Combine(solutionPath + @"\QS.Model\\bin\Debug\QS.Model.dll");
    byte[] fileData = File.ReadAllBytes(modelFile);
    Assembly assembly = Assembly.Load(fileData);

    IEnumerable<Type> modelTypes = assembly.GetTypes().Where(m => !m.IsAbstract && m.IsClass && m.BaseType != null);
    foreach (Type modelType in modelTypes)
    {
        object[] objAttrs = modelType.GetCustomAttributes(typeof(TableAttribute), true);
        if(objAttrs.Length > 0){
            //实例化bll模板
            BLLTemplate bll= new BLLTemplate(modelType.Name);
            string filePath= Path.Combine(currentPath,"bll", bll.FileName);
            //创建文件
            bll.RenderToFile(filePath);
        }
    }
#>

由于TableAttribute在命名空间System.ComponentModel.DataAnnotations.Schema所有需要导入该命名空间 但是导入该命名空间后还是报错 我就不知道是什么原因了 所以我就直接加载了这个dll

如果各位知道不妨告诉博主 博主将感激不尽

这样 生成代码就搞定了 所有的地方都可以用这样的方式生成

在视图里面我们需要字段来显示标签就可以这样

新建Index视图模型叫 IndexViewTemplate.tt

<#+
public class IndexViewTemplate : CSharpTemplate
{

	string name;
    private string[] parme;
    private string[] description;
    public IndexViewTemplate(string modelName,string[] parmes,string[] descriptions)
    {
        name = modelName;
        parme = parmes;
        description  = descriptions;
    }

	/// <summary>
    /// 获取 生成的文件名,根据模型名定义
    /// </summary>
    public string FileName
    {
        get
        { 
            return string.Format("index.cshtml", EntityName);
        }
    }

	/// <summary>
    /// 实体名称
    /// </summary>
	public string EntityName
	{
		get
		{
			return name.Replace("Model", string.Empty);
		}
	}
        public string View1{
            get{
                string parmes = null;
                foreach(string item in description){
                    string newline = "\n";
                    if(item == description[description.Length-1])
                        newline = string.Empty;
                    parmes += $"<th style='text-align:center;'>{item}</th>{newline}";
                }
                return parmes;
            }
        }
        public string List{
            get{
                string parmes = string.Empty;
                for(int i=0;i<parme.Length;i++){
                    string newline = "\n";
                    if(i == parme.Length-1)
                        newline = string.Empty;
                    parmes += $"row.insertCell({i}).innerHTML = n.{parme[i]};{newline}";
                }

                return parmes;
            }
        }
	public override string TransformText()
	{
		base.TransformText();
#>


@using LZH.BASE.Models;
@{
    ViewBag.Title = "Index";
    ViewBag.First = "<#=EntityName #>";
    ViewBag.Second = "<#=EntityName #>";
    Layout = "~/Views/Shared/_Layout.cshtml";
}


@model <#=name#>

<div class="box box-primary">
    <div class="box-header with-border">
        <form class="form-inline">
            <a href="/<#=EntityName #>/Add<#=EntityName #>/" class="btn btn-primary btn-xs"><span class="glyphicon glyphicon-plus-sign"></span> 新增</a>
        </form>
    </div>

    <div class="box-body" style="padding:0px">

        <table data-toggle="table" id="table" style="border:none;100%;margin-bottom:50px;  text-align:center;" cellpadding="0" cellspacing="0" class="list_table">
            <thead>
                <tr style="text-align:center;">
                    <#=View1 #>
                </tr>
            </thead>
            <tbody id="listData"></tbody>
        </table>

    </div>
</div>



@section Js{
    <script type="text/javascript">

        $(document).ready(function () {
            loadData();
        });
        //加载数据
        function loadData() {
            var load = layer.msg('数据加载中,请稍后', { icon: 16, time: 0, shade: [0.3, '#000'] });
            var url = '@Url.Action("GetPageData")';
            $.post(url, function (data) {
                var table = $("#listData");
                if (data.length > 0) {
                    $.each(data, function (index, n) {
                        var row = document.createElement('tr');
                        row.className = "tr";
                        <#=List #>
                        row.insertCell(4).innerHTML = "<a title='修改' class='btn btn-primary btn-xs'   style='margin:0 3px'  data-Id=" + n.Id + "  onclick='edit(this)'><span class='fa fa-edit'></span></a>" +
                        "<a title='删除'  class='btn btn-warning btn-xs' style='margin:0 3px' data-Id=" + n.Id + " onclick='delete1(this)'><span class=' fa fa-trash'></span></a>";
                        table.append(row);
                    });
                    tab();
                }
                layer.close(load);
            });
        }

        function delete1(elemt) {
            layer.confirm('确认删除该数据?', {
                btn: ['确定', '放弃'] //按钮
            }, function () {
                var url = '@Url.Action("Delete<#=EntityName #>")';
                var load = layer.msg('数据提交中,请稍后', { icon: 16, time: 0, shade: [0.3, '#000'] });
                $.post(url, { userId: $(elemt).data('id') }, function (data) {
                    if (data.Status == 0) {
                        layer.msg("删除成功!", { icon: 1, time: 1000, shade: [0.3, '#000'] }, function () {
                            window.location.href = "@Url.Action("Index")";
                        });
                    } else {
                        layer.msg(data.Message, { icon: 2, time: 1000, shade: [0.3, '#000'] });
                    }
                });
            });
        }

        function edit(elemt) {
            window.location.href = "/<#=EntityName #>/Edit<#=EntityName #>/" + $(elemt).data('id');
        }


    </script>
}





<#+
        return this.GenerationEnvironment.ToString();
	}
}
#>

然后修改TextTemplate2.tt代码

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ Import Namespace="System.IO" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Reflection" #>
<#@ Import Namespace="System.Collections.Generic" #>
<#@ import namespace="System.ComponentModel" #>
<#@ assembly name="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.ComponentModel.DataAnnotations.dll" #>
<#@ Import Namespace="System.ComponentModel.DataAnnotations.Schema" #>
<#@ output extension=".txt" #>
//这个必填 导入T4工具
<#@ include file="T4Toolbox.tt" #>
//这里填写bll模型的路径 当前TextTemplate2.tt目录下的Template文件夹里的BLLTemplate1.tt
<#@ include file="Template/IndexViewTemplate.tt" #>


<#
    //当前TextTemplate2.tt所在的模板路径
	var currentPath = Path.GetDirectoryName(Host.TemplateFile);
    //解决方案路径
    string solutionPath = currentPath.Substring(0, currentPath.LastIndexOf("\\"));
    //项目名称
    string projectFullName = currentPath.Substring(currentPath.LastIndexOf("\\") + 1);

    //实体文件所在路径
    string modelFile = Path.Combine(solutionPath + @"\QS.Model\\bin\Debug\QS.Model.dll");
    byte[] fileData = File.ReadAllBytes(modelFile);
    Assembly assembly = Assembly.Load(fileData);

    IEnumerable<Type> modelTypes = assembly.GetTypes().Where(m => !m.IsAbstract && m.IsClass && m.BaseType != null);
    foreach (Type modelType in modelTypes)
    {
        object[] objAttr = modelType.GetCustomAttributes(typeof(TableAttribute), true);
        if(objAttr.Length > 0){
            List<string> parmes = new List<string>();
            List<string> description = new List<string>();
            //获取公共参数
            var pf = modelType.GetProperties();
            foreach (PropertyInfo item in pf)
            {
                object[] objAttrs = item.GetCustomAttributes(typeof(NotMappedAttribute), true);
                if (objAttrs.Length == 0)
                {
                    parmes.Add(item.Name);
                    object[] objs = item.GetCustomAttributes(typeof(DescriptionAttribute), false);
                    if (objs.Length == 0)    //当描述属性没有时,直接返回名称
                    {
                        description.Add(item.Name);
                    }else{
                        DescriptionAttribute descriptionAttribute = (DescriptionAttribute)objs[0];
                        description.Add(descriptionAttribute.Description);
                    }
                }
            }
            //创建index
            string modelName = modelType.Name;
            IndexViewTemplate indexTemplate = new IndexViewTemplate(modelName,parmes.ToArray(),description.ToArray());
            var fileName = indexTemplate.FileName;
            var indexFile = Path.Combine(currentPath,"ModelView",indexTemplate.EntityName, indexTemplate.FileName);
            //判断指定文件夹下面是否创建过该文件
            if(!File.Exists(indexFile)){
                indexTemplate.RenderToFile(indexFile);
            }
        }
    }
#>

好了这样就行了 增删改查视图都是一样的 不过要注意模板里面的FileName字段,这里的所有文件生成都是根据这个字段来的

如果你的实体dll有依赖的 引用的其他程序集 需要加载所有的依赖项才可以

具体参考:https://www.cnblogs.com/zagelover/articles/2726034.html

提个问题:生成需要反射的dll是出现该文件已锁定是怎么回事 我使用的File.ReadAllBytes()应该不会锁定该文件吧

原文地址:https://www.cnblogs.com/qs315/p/9365995.html