使用T4模板基于POCO生成多个类

2024-01-28

当我向数据库添加表时,我正在寻找一种提高工作效率的方法。一般来说,当我添加新表时,我必须执行以下步骤。

  1. 将表添加到数据库(简单)
  2. 创建相应的 EF Code First 类。 (我不使用数据库迁移)
  3. 创建一个与 #2 中创建的 EF 类匹配的 POCO 模型。
  4. 创建存储库类
  5. 为 CQRS 模式创建命令和处理程序
  6. 为新创建的类创建 AutoMapper 地图

我最近创建了一个新网站,其中要求首先使用 EF 数据库,我了解了它如何使用 tt 文件生成类。这让我想到我可以以某种方式使用这些模板(新模板)来生成基本 CRUD 操作的所有标准支持项。问题是我没有创建这些模板的经验,也不知道从哪里开始。

要生成的示例代码:

存储库

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

public interface IUsersRepository : IRepository<Users>
{
}

public class UsersRepository : RepositoryBase<Users>, IUsersRepository
{
    public UsersRepository(IDatabaseFactory databaseFactory)
        : base(databaseFactory)
    {
    }

}

基于 EDMX(或 Code First)生成的实体的基本模型

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

public class User 
{
    public int UserId { get; set; }
    public string UserRole { get; set; }
    public string UserName { get; set; }
}

Command

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

public class AddUpdateUserPayoutCommand : CommandBase, ICommand
{
    public int UserId { get; set; }
    public string UserRole { get; set; }
    public string UserName { get; set; }
}

命令处理程序

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

public class AddUpdateUserHandler: ICommandHandler<AddUpdateUserCommand>
{
    private readonly IUsersRepository _repository;
    private readonly IUnitOfWork _unitOfWork;
    public AddUpdateUserPayoutHandler(IUsersRepository repository, IUnitOfWork unitOfWork)
    {
        _repository = repository;
        _unitOfWork = unitOfWork;
    }
    public ICommandResult Execute(AddUpdateUserCommand command)
    {
        Users entity;
        if (command.UserId == 0)
        {
            entity = AutoMapper.Mapper.Map<Users>(command);
            _repository.Add(entity);
        }
        else
        {
            entity = _repository.Get(x=>x.UserId==command.UserId);
            entity = AutoMapper.Mapper.Map<Users>(command);
            _repository.Update(entity);
        }
        _unitOfWork.Commit(command.UserId);         

        return new CommandResult(true,entity.UserId);
    }
}

Automapper 地图 - 放置在 app_start 中

Mapper.CreateMap<User, AddUpdateUserCommand>();

此示例并不是一个可以剪切粘贴到项目中的解决方案,而是作为一个示例,说明如何编写从数据库模式生成代码的模板。

构建一个快速模板来演示如何生成代码工件。

您可以在这里找到整个项目:https://github.com/mrange/CodeStack/tree/master/q18787460/ModelGenerator https://github.com/mrange/CodeStack/tree/master/q18787460/ModelGenerator

模板本身使用 T4Include.Schema 来获取数据库架构。 SMO 也完全可以合法使用,我只是更喜欢 T4Include.Schema 因为它的性能并且它只依赖于 SqlConnection (T4Include.Schema 是 SqlConnection 的一部分)https://www.nuget.org/packages/T4IncludeTemplate/ https://www.nuget.org/packages/T4IncludeTemplate/).

模板的基本策略是获取所有表并迭代它们生成代码工件。

<#@ include file="$(SolutionDir)\packages\T4IncludeTemplate.1.0.3\T4\Schema.ttinclude"#>

<#

    // The namespace surrounding the code
    var namespaceName               = "ModelGenerator";
    var connectionString            = @"Data Source=localhost\SQLEXPRESS;Initial Catalog=TestDB;Integrated Security=True";
    var schema                      = GetSchema (connectionString);
    Func<string, string> justify    = s => LeftJustify (s, 40);

    var tables                      = schema
        .SchemaObjects
        .Where (so => so.Type == SchemaObject.SchemaObjectType.Table)
        .ToArray ()
        ;
#>

namespace <#=namespaceName#>
{
<#
    foreach (var table in tables)
    {
#>
    /// <summary>
    /// Repository interface for <#=table.Name#>
    /// </summary>
    partial interface I<#=table.Name#>Repository : IRepository<<#=table.Name#>>
    {
    }

    /// <summary>
    /// Repository class for <#=table.Name#>
    /// </summary>
    partial class <#=table.Name#>Repository : RepositoryBase<<#=table.Name#>>, I<#=table.Name#>Repository
    {
    }

    /// <summary>
    /// Poco class for <#=table.Name#>
    /// </summary>
    partial class <#=table.Name#>
    {
<#
    foreach (var column in table.Columns)
    {
#>
        public <#=justify (column.CsTypeName)#> <#=justify (column.Name)#>{ get; set; }
<#
    }
#>
    } 

    /// <summary>
    /// Command class for <#=table.Name#>
    /// </summary>
    partial class <#=table.Name#>Command : CommandBase, ICommand
    {
<#
    foreach (var column in table.Columns)
    {
#>
        public <#=justify (column.CsTypeName)#> <#=justify (column.Name)#> { get; set; }
<#
    }
#> 
    }

    /// <summary>
    /// Command handler class for <#=table.Name#>
    /// </summary>
    partial class <#=table.Name#>CommandHandler : ICommandHandler<<#=table.Name#>Command>
    {
        private readonly IUsersRepository _repository;
        private readonly IUnitOfWork _unitOfWork;
        public <#=table.Name#>CommandHandler(IUsersRepository repository, IUnitOfWork unitOfWork)
        {
            _repository = repository;
            _unitOfWork = unitOfWork;
        }

        public ICommandResult Execute(<#=table.Name#>Command command)
        {
            <#=table.Name#> entity;

<#
    var identityColumn = table.Columns.FirstOrDefault (c => c.IsIdentity);
    if (identityColumn == null)
    {
#>
@@@ ERROR__NO_IDENTITY_COLUMN_FOUND_FOR: <#=table.FullName#>
<#
    }
    else
    {
#>
            if (command.<#=identityColumn.Name#> == 0)
            {
                entity = AutoMapper.Mapper.Map<<#=table.Name#>>(command);
                _repository.Add(entity);
            }
            else
            {
                entity = _repository.Get(x=>x.UserId==command.<#=identityColumn.Name#>);
                entity = AutoMapper.Mapper.Map<<#=table.Name#>>(command);
                _repository.Update(entity);
            }
            _unitOfWork.Commit(command.<#=identityColumn.Name#>);         

            return new CommandResult(true,entity.<#=identityColumn.Name#>);
<#
    }
#>
        }
    }
<#
    }
#>
}

<#+

    static Schema GetSchema (string connectionString) 
    {
        using (var connection = new SqlConnection (connectionString))
        {
            connection.Open ();

            return new Schema (connection);
        }
    }


#>

最后生成的代码如下所示(对于我的测试数据库,只有一个表:CUS_Customer)

// ############################################################################
// #                                                                          #
// #        ---==>  T H I S  F I L E  I S   G E N E R A T E D  <==---         #
// #                                                                          #
// # This means that any edits to the .cs file will be lost when its          #
// # regenerated. Changes should instead be applied to the corresponding      #
// # template file (.tt)                                                      #
// ############################################################################











namespace ModelGenerator
{
    /// <summary>
    /// Repository interface for CUS_Customer
    /// </summary>
    partial interface ICUS_CustomerRepository : IRepository<CUS_Customer>
    {
    }

    /// <summary>
    /// Repository class for CUS_Customer
    /// </summary>
    partial class CUS_CustomerRepository : RepositoryBase<CUS_Customer>, ICUS_CustomerRepository
    {
    }

    /// <summary>
    /// Poco class for CUS_Customer
    /// </summary>
    partial class CUS_Customer
    {
        public System.Int64                             CUS_ID                                  { get; set; }
        public System.String                            CUS_FirstName                           { get; set; }
        public System.String                            CUS_LastName                            { get; set; }
        public System.DateTime                          CUS_Born                                { get; set; }
        public System.DateTime                          CUS_Created                             { get; set; }
    } 

    /// <summary>
    /// Command class for CUS_Customer
    /// </summary>
    partial class CUS_CustomerCommand : CommandBase, ICommand
    {
        public System.Int64                             CUS_ID                                   { get; set; }
        public System.String                            CUS_FirstName                            { get; set; }
        public System.String                            CUS_LastName                             { get; set; }
        public System.DateTime                          CUS_Born                                 { get; set; }
        public System.DateTime                          CUS_Created                              { get; set; }

    }

    /// <summary>
    /// Command handler class for CUS_Customer
    /// </summary>
    partial class CUS_CustomerCommandHandler : ICommandHandler<CUS_CustomerCommand>
    {
        private readonly IUsersRepository _repository;
        private readonly IUnitOfWork _unitOfWork;
        public CUS_CustomerCommandHandler(IUsersRepository repository, IUnitOfWork unitOfWork)
        {
            _repository = repository;
            _unitOfWork = unitOfWork;
        }

        public ICommandResult Execute(CUS_CustomerCommand command)
        {
            CUS_Customer entity;

            if (command.CUS_ID == 0)
            {
                entity = AutoMapper.Mapper.Map<CUS_Customer>(command);
                _repository.Add(entity);
            }
            else
            {
                entity = _repository.Get(x=>x.UserId==command.CUS_ID);
                entity = AutoMapper.Mapper.Map<CUS_Customer>(command);
                _repository.Update(entity);
            }
            _unitOfWork.Commit(command.CUS_ID);         

            return new CommandResult(true,entity.CUS_ID);
        }
    }
}

如果您从 github 拉取该项目并将连接字符串更新为与您相关的内容,它应该会为您生成代码。如果您遇到任何问题,请回复此帖子。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用T4模板基于POCO生成多个类 的相关文章

随机推荐

  • 按下按钮刷新 tkinter 框架

    我正在使用来自的代码在 tkinter 中的两个框架之间切换 https stackoverflow com questions 7546050 switch between two frames in tkinter制作我的图形用户界面
  • 在 Swift 中将参数传递给选择器

    我正在构建一个应用程序来跟踪大学课程的阅读作业 每个 ReadingAssignment 都包含一个 Bool 值 指示读者是否已完成阅读作业 ReadingAssignments 被收集到 WeeklyAssignment 数组中 我希望
  • 具有相同标签的不同散点图标记

    我遇到了 类似 的问题Matplotlib 一个标签具有多个不同标记的图例 https stackoverflow com questions 9262307 matplotlib legend with multiple differen
  • 多个域的集成 Windows 身份验证

    我有一个针对域 A 用户的 Asp net 网站 具有集成 Windows 身份验证 现在B域的用户需要访问该网站 但域B用户访问网站时会弹出窗口输入验证信息 我的问题是 如何配置IIS或Windows Server 让B域用户像A域用户一
  • XAML 文件的智能感知 (Xamarin.Forms)

    在 Visual Studio 15 中 如何让 XAML Intellisense 适用于 Xamarin Forms 中的 XAML 文件 编辑 将答案与问题分开 这个解决方案是在这个论坛 https social msdn micro
  • 如何检测 Angular 中属性的更改

    我有一个带有子组件的组件timeline
  • $null 应该位于相等比较的左侧吗? (-eq 与数组)

    与同事讨论 应该 null是在支票的左边还是右边 有什么例子可以说明为什么这很重要吗 abc null null eq abc True abc eq null True All ok abc 6 7 null 8 9 null eq ab
  • 使用 NPOI 将图像插入 Excel 文件

    我正在使用 C 在 Visual Studio 2010 中编写一个程序 并且正在使用 NPOI 库 我正在尝试将图像插入到 Excel 文件中 我尝试了两种不同的方法 但都不起作用 Method 1 HSSFPatriarch patri
  • 服务重启后 Docker 节点宕机

    我的服务器似乎空间不足 并且某些已部署的 Docker 堆栈出现了一些问题 我花了一段时间才弄清楚 但最终我做到了 并删除了一些容器和图像以释放一些空间 我能够跑service docker restart它起作用了 然而 也存在一些问题
  • 通过java应用程序发送附有excel文件的电子邮件 - 不起作用

    我试图通过Java应用程序发送一封邮件 其中包含excel文件作为附件 而不实际创建该文件 excel文件中的数据来自数据库 我可以发送带有附件的邮件 但文件是文本 制表符分隔 格式 但我希望该文件仅为 Excel 格式 请帮忙 以下是代码
  • 在 Java 调试器中,如何忽略从未通过我的代码的异常

    我目前正在使用 IntelliJ IDEA 进行 Java 开发 但我也对针对其他 IDE 的答案或调试 Java 代码的一般概念感兴趣 因为我在许多 IDE 中都错过了这个功能 所以我不确定在从其他语言转移我的调试习惯时是否错过了工作流程
  • Google Dataflow(Apache Beam)JdbcIO批量插入mysql数据库

    我正在使用 Dataflow SDK 2 X Java API Apache Beam SDK 将数据写入 mysql 我创建了基于管道Apache Beam SDK 文档 https beam apache org documentati
  • 使用 window.open() 的多个窗口

    众所周知 如果您单击嵌入其中的提交按钮onClick windown open 这将打开一个新窗口 其中包含您指定的所有可爱属性 但是 如果继续单击父窗口并再次单击 提交 按钮而不关闭先前的弹出窗口 则同一窗口将被新数据覆盖 现在我需要一种
  • 词汇量和嵌入维度之间的首选比例是多少?

    例如使用时gensim word2vec或用于训练嵌入向量的类似方法我想知道什么是好的比率 或者嵌入维度与词汇量之间是否有首选比率 随着更多数据的出现 这种情况会如何变化 由于我仍在讨论这个主题 因此在训练嵌入向量时如何选择合适的窗口大小
  • 哪些 OpenGL ES 2.0 纹理格式可进行颜色、深度或模板渲染?

    From OpenGL ES 2 0 规范 http www khronos org registry gles specs 2 0 es full spec 2 0 25 pdf第 4 4 5 节 表 4 5 中未列出的格式 包括压缩的内
  • 如何将两个日期列表合并为一系列日期间隔?

    我有开始日期列表和结束日期列表 他们已经排序了 start dates datetime date 2009 11 5 datetime date 2009 11 13 datetime date 2009 11 25 datetime d
  • 实体框架:如何在提交之前检查值是否存在

    我正在使用存储库模式 我有一个国家 地区存储库 我正在使用服务来提交该存储库 我应该在哪里检查该国家 地区是否已存在于数据库中 我会抛出异常吗 有没有一种方法可以在一次数据库调用中做到这一点 如果不存在则检查并插入 如果可以的话 可以在服务
  • 使用区域设置来检测是否使用英制单位

    我正在开发一个应用程序 想要以厘米 cm 或英寸 为单位显示长度 有没有办法从区域设置中选择正确的单位 无论如何 我还将输入一个选项 以便用户可以覆盖区域设置 美国 利比里亚和缅甸应使用英制单位 而世界其他国家应使用正常单位 一种方法是将此
  • 将 CSV 转换为 RDF,其中一列是一组值

    我想将 CSV 转换为 RDF 事实上 该 CSV 的一列是一组用分隔符 在我的例子中为空格符 连接的值 以下是 CSV 示例 带标题 col1 col2 col3 A B C D John M X Y Z Jack 我希望转换过程创建一个
  • 使用T4模板基于POCO生成多个类

    当我向数据库添加表时 我正在寻找一种提高工作效率的方法 一般来说 当我添加新表时 我必须执行以下步骤 将表添加到数据库 简单 创建相应的 EF Code First 类 我不使用数据库迁移 创建一个与 2 中创建的 EF 类匹配的 POCO