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;width: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()应该不会锁定该文件吧