如何编写 T4 模板以从 Entityframework 6 创建 DTO?
How to write a T4 template to create DTO's from Entityframework 6?
我有一个大型数据库,我在 Entityframework 中使用数据库优先模型。它位于 Internet 服务器上并通过 WCF 进行通信。域模型对实体、存储过程和 columns/properties.
的名称使用全部小写字母
在我的客户端应用程序中,我希望使用标准的 PascalCase 命名约定。
T4 模板能否使用正确的命名约定从 Entityframework 创建数据传输对象?
如果是这样,有人可以给我一个如何写的起点吗?
明确一点,我不想更改 Entityframework 生成的任何代码,而是使用 [=34= 添加简单的 POCO 类 并使用适当的驼峰命名法] 模型作为另一个文件的输入,然后可以被 WCF 服务引用,也可能被 Automapper(或类似的东西)引用。
感谢您的任何建议。
- 数据库:PostgreSQL 9.5
- 数据库接口:Npgsql 3.0.5
- .NET 4.5
- Entityframework 6.0
代替任何人回答这个问题并希望帮助像我这样的其他新手,这是我创建 T4 转换的方法,DTOclasses.tt 只产生简单的 class 定义。
注意:这不是替换 .edmx 的 .tt 文件,而是 运行 在 .edmx 模板生成 .edmx 文件之后。 (我不想更改用于生成域模型的任何代码)。
Visual Studio 2015 年
Entityframework 6.0
.NET 框架 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 (i.e., 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<EntityType>(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 中)完全满足我的需要。 :)
我有一个大型数据库,我在 Entityframework 中使用数据库优先模型。它位于 Internet 服务器上并通过 WCF 进行通信。域模型对实体、存储过程和 columns/properties.
的名称使用全部小写字母在我的客户端应用程序中,我希望使用标准的 PascalCase 命名约定。
T4 模板能否使用正确的命名约定从 Entityframework 创建数据传输对象?
如果是这样,有人可以给我一个如何写的起点吗?
明确一点,我不想更改 Entityframework 生成的任何代码,而是使用 [=34= 添加简单的 POCO 类 并使用适当的驼峰命名法] 模型作为另一个文件的输入,然后可以被 WCF 服务引用,也可能被 Automapper(或类似的东西)引用。
感谢您的任何建议。
- 数据库:PostgreSQL 9.5
- 数据库接口:Npgsql 3.0.5
- .NET 4.5
- Entityframework 6.0
代替任何人回答这个问题并希望帮助像我这样的其他新手,这是我创建 T4 转换的方法,DTOclasses.tt 只产生简单的 class 定义。
注意:这不是替换 .edmx 的 .tt 文件,而是 运行 在 .edmx 模板生成 .edmx 文件之后。 (我不想更改用于生成域模型的任何代码)。
Visual Studio 2015 年 Entityframework 6.0 .NET 框架 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 (i.e., 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<EntityType>(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 中)完全满足我的需要。 :)