简体   繁体   English

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

[英]Using T4 Templates to Generate multiple classes based on POCO

Im looking for a way to increase productivity when I add a table to my database. 我正在寻找一种方法来提高生产力,当我向我的数据库添加一个表。 Generally, when I add a new table I have to perform the following steps. 通常,当我添加新表时,我必须执行以下步骤。

  1. Add table to the database (simple) 将表添加到数据库(简单)
  2. Create the corresponding EF Code First class. 创建相应的EF Code First类。 (i dont use db migrations) (我不使用db迁移)
  3. Create a POCO model that matches the EF class created in #2. 创建一个与#2中创建的EF类匹配的POCO模型。
  4. Create repository class 创建存储库类
  5. Create Commands and Handlers for CQRS pattern 为CQRS模式创建命令和处理程序
  6. Create AutoMapper maps for the newly created classes 为新创建的类创建AutoMapper映射

I recently created a new website where the requirements were to use EF Database first and I saw how it was using the tt files to generate the classes. 我最近创建了一个新网站,其中要求首先使用EF数据库,我看到它是如何使用tt文件生成类的。 That got me thinking that I could somehow use those templates (new ones) to generate all the standard support items for basic CRUD operations. 这让我想到我可以以某种方式使用这些模板(新模板)来生成基本CRUD操作的所有标准支持项。 Trouble is I have no experience creating these templates and have no idea where to start. 麻烦的是我没有创建这些模板的经验,也不知道从哪里开始。

Sample Code to be generated: 要生成的示例代码:

Repository 知识库

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

}

Basic model based on entity generated from EDMX (or Code First) 基于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; }
}

Command Handler 命令处理程序

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 Maps - Placed in app_start Automapper Maps - 放置在app_start中

Mapper.CreateMap<User, AddUpdateUserCommand>();

This example isn't meant to be a solution that one can cutnpaste into a project but as an example on how one could write a template that generate code from database schema. 这个例子并不是一个可以切入项目的解决方案,而是作为一个例子来说明如何编写一个从数据库模式生成代码的模板。

Built a quick template to demonstrate how you might go about to generate the code artifacts. 构建了一个快速模板,演示了如何生成代码工件。

You can find the whole project here: https://github.com/mrange/CodeStack/tree/master/q18787460/ModelGenerator 你可以在这里找到整个项目: https//github.com/mrange/CodeStack/tree/master/q18787460/ModelGenerator

The template itself use T4Include.Schema to get the db schema. 模板本身使用T4Include.Schema来获取数据库模式。 SMO is also completely legit to use as well, I just prefer T4Include.Schema because of the performance and that it only relies SqlConnection (T4Include.Schema is part of https://www.nuget.org/packages/T4IncludeTemplate/ ). SMO也是完全合法的使用,我只是喜欢T4Include.Schema因为性能而且它只依赖于SqlConnection(T4Include.Schema是https://www.nuget.org/packages/T4IncludeTemplate/的一部分)。

The basic strategy of the template is to get hold of all tables and iterate over them generating the code artifact. 模板的基本策略是获取所有表并迭代它们以生成代码工件。

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


#>

Finally the generated code looks like this (for my test db that only has one table: CUS_Customer) 最后,生成的代码看起来像这样(对于我的测试数据库,只有一个表: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);
        }
    }
}

If you pull the project from github and update the connection string to something that is relevant to you it should generate the code for you. 如果从github拉出项目并将连接字符串更新为与您相关的内容,则应为您生成代码。 If you run into any issues just respond to this post. 如果您遇到任何问题,请回复此帖。

What you want is in the road map of the Entity Interface Generator 您想要的是实体接口生成器的路线图

https://entityinterfacegenerator.codeplex.com https://entityinterfacegenerator.codeplex.com

This project contains customized T4 templates which can generate interfaces and attributes for the DbContext class and entity classes. 该项目包含自定义的T4模板,可以为DbContext类和实体类生成接口和属性。 It does not, but will soon, generate generic repositories. 它不会,但很快就会生成通用存储库。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM