我正在开发一些代码生成器,用于基于数据库表生成模型、控制器和视图,这样我就可以创建一个 Asp.Net MVC3 网站。我现在可以使用 CodeDOM 生成模型和控制器,但是为了生成视图,我需要一些东西来制作模板,比如从 .cs 生成 .cshtml,我认为 T4 是个好主意,但我的一些同事坚持不使用 T4,是还有其他方法吗?谢谢
5 回答
我不确定他们为什么反对使用 T4,因为包括 Entity Framework 在内的许多代码库都使用它们。听起来你在做我刚做完的事情。我喜欢使用 Pre-Processed T4 模板,因此我能够将数据从 C# 代码输入到模板中,并以这种方式生成文件。这允许您有多个文件输出和基本参数来传递数据。
我使用它的方式是..我创建了一个类,用于收集有关数据库的所有信息..要包含或排除哪些表..然后是每个列的信息,如 pk 或 identity 可为空等。我将预处理的 t4 模板插入到该信息中,该信息能够生成所有 SQL、视图、模型、控制器信息……并且每当数据库更改时……我只需运行我的控制台应用程序并重新生成它。
预处理: http: //odetocode.com/Blogs/scott/archive/2011/01/03/preprocessed-t4-templates.aspx
实体框架:http: //msdn.microsoft.com/en-us/data/gg558520.aspx
MVCScaffolding:http: //blog.stevensanderson.com/2011/04/06/mvcscaffolding-overriding-the-t4-templates/
T4MVC: http ://mvccontrib.codeplex.com/wikipage?title=T4MVC
我再次知道这无助于回答您的问题,但 T4 非常棒,我很想听听关于为什么不使用 T4 的争论。它甚至是内置的!
顺便说一句,这里有一些智能!: http: //t4-editor.tangible-engineering.com/T4-Editor-Visual-T4-Editing.html
如果您有任何问题,请随时联系我,我喜欢 T4,我愿意回答我能回答的任何问题。
这是我用来生成我的 POCO 模型的模板示例。由于使用我的普通 c# 方法传入数据的预处理能力,已经提取了很多内容。这个模板为我创建了 55 个模型,基于数据库中的表。
我的“SchemeCollector”使用我创建的 DatabaseInfo、TableInfo 和 ColumnInfo 类来保存我需要的所有模式。然后我有 9 个其他 t4 模板,它们也使用 SchemaCollector 类来填充数据。
这是我用来将数据传递到模板中进行生成的扩展。我有这一切设置也可以使用 XML 文件进行配置,但我只是希望它真正可重用是不必要的。
public partial class PocoGenerator
{
public string Namespace { get; set; }
public string Inherit { get; set; }
public DatabaseInfo Schema { get; set; }
public bool Contract { get; set; }
public string SavePath { get; set; }
}
这是我用来调用和填充模板并保存它的方法。
static void GeneratePoco(Config config)
{
var template = config.Poco;
template.Schema = config.DatabaseInfo;
File.WriteAllText(template.SavePath, template.TransformText());
Console.WriteLine(" - POCOs generated for " + config.DatabaseInfo.DatabaseName + " complete");
}
这是模板
<#@ template debug="true" hostSpecific="true" #>
<#@ output extension=".cs" #>
<#@ Assembly Name="System.Core.dll" #>
<#@ Assembly Name="System.Windows.Forms.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Diagnostics" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ assembly name="System.Xml.dll" #>
<#@ assembly name="System.Data.dll" #>
<#@ import namespace="System.Data" #>
<#@ import namespace="System.Data.SqlClient" #>
<#@ import namespace="CodeGenerator.Utilities" #>
using System;
using System.Runtime.Serialization;
namespace My.Models
{ <#
List<TableInfo> tables = Schema.Tables;
#>
//#########################################################################################################
// This file has been generated from the tables contained in the <#= Schema.DatabaseName #> database.
// Changes to this file will be overwritten when the file is regenerated. Generated: <#= DateTime.Now #>
//#########################################################################################################
<#
foreach (TableInfo table in tables)
{
#>
[DataContract]
public class <#= table.Name #> : IConfigTable
{
<#
PushIndent(" ");
foreach (ColumnInfo col in table.Columns)
{
if(col.IsKey || col.IsIdentity)
WriteLine("[Key]");
WriteLine("[DataMember]");
if(col.IsNullable && col.Type != "string")
WriteLine("public " + col.Type + "? " + col.Name+ " { get; set; }");
else
WriteLine("public " + col.Type + " " + col.Name+ " { get; set; }");
}PopIndent();#>
}
<# } #>
}
我们有类似的任务,我们正在创建基于带有表单定义的输入 json 文件的动态 Web 表单。编辑器指定应在表单上呈现的不同控件(控件包含不同的属性、操作、验证器)。下面我将尝试描述我们逻辑的基本过程:
- 反序列化和验证 json 文件。
- 准备将传递给 T4 模板的数据。
- 从数据生成 MVC 模型和控制器(步骤 2)。
- 生成其他类(例如,一些帮助器、模型中的复杂类型)。
- 添加到程序集嵌入资源,例如数据源等,图像等等。
- 编译上面的所有东西。
- 将 dll 放入模型文件夹中。
- 重新启动站点。
模型中的所有属性都有其[UIHint]属性和部分视图的名称。我们有大约 10 个知道如何表示每个属性的局部视图。为了支持这个逻辑,我们扩展了 ViewEngine 和 ModelMetadata 提供者。
ViewEngine 在附加文件夹中查找视图。ModelMetada 提供程序添加到“AdditionalValues”自定义属性。
我们的模型视图只有一行
@Html.EditorForModel()
我们已经覆盖了 Object.cshtml 来处理“深度绑定”。最困难的部分是集合项目是复杂类型的集合。
我们广泛使用了 Code smith,还编写了一个插件。使用 t4 虽然您可以简单地生成类然后删除模板 - 为什么反对 T4?
当然,我通过使用不错的扩展RazorGenerator将 Razor 用于我的所有代码生成(和电子邮件生成等) 。它允许您将此扩展指定为“自定义工具”,并根据您的.cshtml
输入生成一个结果 C# 类,您可以调用(并传入 a @model
)将文本转换为您喜欢的任何输出。(在你的情况下有点讽刺的是,这将是剃刀 => 剃刀转换)