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

3
我有一个大型数据库,正在使用 Entityframework 的 数据库先建模 ,这个数据库位于互联网服务器上,并通过 WCF 通信。域模型将实体、存储过程和列/属性的名称全部使用小写字母。
在客户端应用程序中,我希望使用标准 PascalCase 命名约定。
T4 模板能否创建正确命名约定的数据传输对象?
如果可以的话,能否请有人给我一个编写它的起点?
需要明确的是,我不想更改 Entityframework 生成的任何代码,而是添加简单的 POCO 类,并使用 Entityframework 模型作为输入产生适当的 CamelCase 命名约定。这个文件可以由 WCF 服务引用,也可以由 Automapper(或类似工具)引用。
感谢任何建议。
  • 数据库: PostgreSQL 9.5
  • 与数据库接口:Npgsql 3.0.5
  • .NET 4.5
  • Entityframework 6.0
1个回答

1

如果没有任何人回答,希望能帮助像我这样的新手,我将介绍如何创建一个 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 (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中),以实现我所需的功能。:)

嗨,这会为每个DTO创建一个单独的部分类吗?我的实体来自Sql Server,这里会有任何差异或更改吗? - Transformer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接