如何编写T4模板以从Entityframework 6创建DTO?

我有一个大型数据库,我在Entityframework中使用数据库优先模型。 它位于Internet服务器上并通过WCF进行通信。 域模型使用所有小写字母作为实体,存储过程和列/属性的名称。

在我的客户端应用程序中,我希望使用标准PascalCase作为命名约定。

T4模板是否可以使用正确的命名约定从Entityframework创建数据传输对象?

如果是这样,有人可以给我一个关于如何写它的起点吗?

为了清楚起见,我不想更改Entityframework生成的任何代码,而是使用Entityframework模型作为对另一个文件的输入添加具有相应CamelCase命名的简单POCO类,然后可以由WCF服务引用也许是Automapper(或类似的东西)。

谢谢你的任何建议。

  • 数据库:PostgreSQL 9.5
  • 数据库接口:Npgsql 3.0.5
  • .NET 4.5
  • Entityframework 6.0

代替任何人回答这个并希望帮助像我这样的其他新手,这就是我创建T4变换所做的,DTOclasses.tt只产生简单的类定义。

注意:这不是替换.edmx的.tt文件,而是在.edmx模板生成.edmx文件后运行。 (我不想更改用于生成域模型的任何代码)。

Visual Studio 2015 Entityframework 6.0 .NET Framework 4.6.1

♦ Notes on Creating DTOclassess.tt This T4 transform was created by first copying the working transform used to build the entity model, MedicalOfficeModel.tt. Then, parts of it that were not needed for creation of POCO classes to be used for DTO's (data transfer objects) were removed. ♦ Changes made to DTOclassses.tt • Adding "DTO" to namespace. public void BeginNamespace(CodeGenerationTools code) { var codeNamespace = String.Format("{0}.{1}",code.VsNamespaceSuggestion(), "DTO"); if (!String.IsNullOrEmpty(codeNamespace)) { #> namespace <#=code.EscapeNamespace(codeNamespace)#> { <#+ PushIndent(" "); } } • Put all POCO classes in single file DTOclasses.cs <# EndNamespace(code); } fileManager.Process(false); <--**False stops the splitting of classes into different files. Default is true. #> • Change the property naming code: public string Property(EdmProperty edmProperty) { return string.Format( CultureInfo.InvariantCulture, "{0} {1} {2} {{ {3}get; {4}set; }}", Accessibility.ForProperty(edmProperty), _typeMapper.GetTypeName(edmProperty.TypeUsage), GetPascalCase(_code.Escape(edmProperty)), _code.SpaceAfter(Accessibility.ForGetter(edmProperty)), _code.SpaceAfter(Accessibility.ForSetter(edmProperty))); } • Change the class naming code: public string EntityClassOpening(EntityType entity) { return string.Format( CultureInfo.InvariantCulture, "{0} {1}partial class {2}{3}", Accessibility.ForType(entity), _code.SpaceAfter(_code.AbstractOption(entity)), GetPascalCase(_code.Escape(entity)), _code.StringBefore(" : ", _typeMapper.GetTypeName(entity.BaseType))); } • Removed all the navigational stuff. Replaced everything above the helper functions (ie, above <#+) with: <#@ template debug="false" hostspecific="true" language="C#" #> <#@ assembly name="System.Core" #> <#@ import namespace="System.Linq" #> <#@ import namespace="System.Text" #> <#@ import namespace="System.Collections.Generic" #> <#@ import namespace="System.Text.RegularExpressions" #> <#@ include file="EF6.Utility.CS.ttinclude" #> <#@ output extension=".cs" #> <# const string inputFile = @"MedicalOfficeModel.edmx"; var textTransform = DynamicTextTransformation.Create(this); var code = new CodeGenerationTools(this); var ef = new MetadataTools(this); var typeMapper = new TypeMapper(code, ef, textTransform.Errors); var fileManager = EntityFrameworkTemplateFileManager.Create(this); var itemCollection = new EdmMetadataLoader(textTransform.Host, textTransform.Errors).CreateEdmItemCollection(inputFile); var codeStringGenerator = new CodeStringGenerator(code, typeMapper, ef); if (!typeMapper.VerifyCaseInsensitiveTypeUniqueness(typeMapper.GetAllGlobalItems(itemCollection), inputFile)) { return string.Empty; } WriteHeader(codeStringGenerator, fileManager); foreach (var entity in typeMapper.GetItemsToGenerate(itemCollection)) { fileManager.StartNewFile(entity.Name + ".cs"); BeginNamespace(code); #> <#=codeStringGenerator.UsingDirectives(inHeader: false)#> <#=codeStringGenerator.EntityClassOpening(entity)#> { <# var simpleProperties = typeMapper.GetSimpleProperties(entity); if (simpleProperties.Any()) { foreach (var edmProperty in simpleProperties) { #> <#=codeStringGenerator.Property(edmProperty)#> <# } } #> } <# EndNamespace(code); } fileManager.Process(false); #> ♦ Added my helper function: <#+ public static string GetPascalCase(string name) { return Regex.Replace(name, @"^\w|_\w", (match) => match.Value.Replace("_", "").ToUpper()); } #> 

当一切都完成后,这完全运行(在VS2015中)完全按照我的需要进行操作。 🙂