如何编写T4模板从Entityframework 6创建DTO? [英] How to write a T4 template to create DTO's from Entityframework 6?

查看:140
本文介绍了如何编写T4模板从Entityframework 6创建DTO?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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



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



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



要清楚,我不想更改任何代码Entityframework生成,而是使用Entityframework模型将Entityframework模型添加到适合的CamelCase命名的简单POCO类,作为另一个文件的输入,然后可以由WCF服务引用,也可能由Automapper(或类似的东西)引用。



感谢任何建议。




  • 数据库:PostgreSQL 9.5

  • 数据库接口:Npgsql 3.0.5

  • .NET 4.5

  • Entityframework 6 .0


解决方案

代替任何回答这个问题的人,希望帮助任何其他新手像我自己,这里是我创建一个T4变换,DTOclasses.tt只产生简单的类定义。



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



Visual Studio 2015
Entityframework 6.0
.NET Framework 4.6.1

 ♦创建DTOclassess.tt 

的注意事项此T4变换是通过首次复制创建的用于构建实体模型的工作变换,MedicalOfficeModel.tt。
然后,删除了用于创建用于DTO(数据传输对象)的POCO类所不需要的部分。

♦对DTOclassses.tt

所做的更改•将DTO添加到命名空间。
public void BeginNamespace(CodeGenerationTools code)
{
var codeNamespace = String.Format({0}。{1},code.VsNamespaceSuggestion(),DTO);
if(!String.IsNullOrEmpty(codeNamespace))
{
#>
命名空间<#= code.EscapeNamespace(codeNamespace)#>
{
<#+
PushIndent();
}
}

•将所有POCO类放在单个文件中DTOclasses.cs

<#
EndNamespace(code);
}

fileManager.Process(false); < - ** False停止将类分成不同的文件。默认值为true。

#>

•更改属性命名代码:

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) ));
}

•更改类命名代码:

public string EntityClassOpening(EntityType entity)
{
return string.Format(
CultureInfo.InvariantCulture,
{0} {1}部分类{2} {3},
Accessibility.ForType(entity),
_code.SpaceAfter(_code.AbstractOption (实体)),
GetPascalCase(_code.Escape(entity)),
_code.StringBefore(:,_typeMapper.GetTypeName(entity.BaseType)));
}

•删除了所有导航的东西。替换为辅助函数之上的所有内容(即<#+)以上:
<#@ template debug =falsehostspecific =truelanguage =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(typeMapper.GetItemsToGenerate< EntityType>(itemCollection)中的var实体)
{
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);

#>

♦增加了我的帮助函数:
<#+

public static string GetPascalCase(string name)
{
return Regex。替换(name,@^ \w | _\w,
(match)=> match.Value.Replace(_,).ToUpper());
}
#>

当所有的完成后,这完全可以运行(在VS2015中)来完成我所需要的。 :)


I have a large database from which I am using a database-first model in Entityframework. This sits on an internet server and communicates through WCF. The domain model uses all lowercase letters for the names of the entities, stored procedures, and columns/properties.

In my client applications, I wish to use the standard PascalCase for the naming convention.

Could a T4 template create the data transfer objects from the Entityframework with the correct naming convention?

If so, could someone please give me a starting point on how to write it?

Just to be clear, I am not wanting to change any of the code that the Entityframework generated, but rather add simple POCO classes with the appropriate CamelCase naming using the Entityframework model as input to another file which can then be referenced by the WCF service and perhaps by Automapper (or something similar).

Thanks for any suggestions.

  • Database: PostgreSQL 9.5
  • Interface to database: Npgsql 3.0.5
  • .NET 4.5
  • Entityframework 6.0

解决方案

In lieu of anybody answering this and to hopefully help any other newbie like myself, here is what I did to create a T4 transform, DTOclasses.tt that yields only simple class definitions.

Note: this is NOT replacing the .tt files of the .edmx, but rather is run after the .edmx templates have produced the .edmx file. (I did not want to change any of the code used to produce the domain model).

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 (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());
                        }
                    #>

When all is done, this runs perfectly (in VS2015) to do exactly what I needed. :)

这篇关于如何编写T4模板从Entityframework 6创建DTO?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆