使用T4模板的基础上POCO生成多个班 [英] Using T4 Templates to Generate multiple classes based on POCO

查看:217
本文介绍了使用T4模板的基础上POCO生成多个班的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

林寻找一种方式来提高生产率,当我添加一个表到我的数据库。一般来说,当我添加一个新表我必须执行以下步骤。




  1. 添加表到数据库中(简单)

  2. 创建相应的EF代码优先类。 (我不使用分贝迁移)

  3. 创建,在#2中创建的EF类相匹配的POCO模型。

  4. 创建repository类

  5. 创建命令和处理程序进行CQRS模式

  6. 为新创建的类创建AutoMapper地图



我最近创建了一个新网站,要求是首先使用EF数据库,我看到它是如何使用TT文件生成的类。这让我以为我能以某种方式使用这些模板(新的),生成所有基本的CRUD操作的标准的支持项目。要产生麻烦的是我没有经验创建这些模板,不知道从哪里开始。



示例代码:



 使用系统; 
使用System.Collections.Generic;
使用System.Linq的;
使用System.Text;

公共接口IUsersRepository:IRepository<用户>
{
}

公共类UsersRepository:RepositoryBase<用户>中IUsersRepository
{
公共UsersRepository(IDatabaseFactory databaseFactory)
:基地( databaseFactory)
{
}

}

根据从EDMX(或代码第一次)生成的实体的基本型

 使用系统; 
使用System.Collections.Generic;
使用System.Linq的;
使用System.Text;

公共类用户
{
公众诠释用户ID {搞定;组; }
公共字符串的UserRole {搞定;组; }
公共字符串用户名{获得;组; }
}



命令



 使用系统; 
使用System.Collections.Generic;
使用System.Linq的;
使用System.Text;

公共类AddUpdateUserPayoutCommand:CommandBase,ICommand的
{
公众诠释用户ID {搞定;组; }
公共字符串的UserRole {搞定;组; }
公共字符串用户名{获得;组; }
}



命令处理程序



 使用系统; 
使用System.Collections.Generic;
使用System.Linq的;
使用System.Text;

公共类AddUpdateUserHandler:ICommandHandler< AddUpdateUserCommand>
{
私人只读IUsersRepository _repository;
私人只读IUnitOfWork _unitOfWork;
公共AddUpdateUserPayoutHandler(IUsersRepository库,IUnitOfWork的UnitOfWork)
{
_repository =库;
_unitOfWork =的UnitOfWork;
}
公共ICommandResult执行(AddUpdateUserCommand命令)
{
中的用户实体;
如果(command.UserId == 0)
{
实体= AutoMapper.Mapper.Map<用户>(命令);
_repository.Add(实体);
}
,否则
{
实体= _repository.Get(X => x.UserId == command.UserId);
实体= AutoMapper.Mapper.Map<用户>(命令);
_repository.Update(实体);
}
_unitOfWork.Commit(command.UserId);

返回新CommandResult(真,entity.UserId);
}
}



Automapper地图 - 摆在app_start

  Mapper.CreateMap<使用者,AddUpdateUserCommand>(); 


解决方案

这个例子并不是要一个解决方案,可以cutnpaste成一个项目,但因为在一个如何编写生成数据库架构的代码模板的例子。



内置快速模板为了证明你怎么可能去生成代码工件



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



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



模板的基本策略是让所有表的保持,在它们之间迭代生成代码神器。

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

<#

//周围的代码
VAR namespaceName =ModelGenerator的命名空间;
变种的connectionString = @数据源= localhost\SQLEXPRESS;初始目录= TESTDB;集成安全性=真;
VAR模式=的getSchema(的connectionString);
Func键<字符串,字符串>证明= S = GT; LeftJustify(S,40);

无功表=架构
.SchemaObjects
。凡(所以=> so.Type == SchemaObject.SchemaObjectType.Table)
.ToArray()
;
#>

&命名空间LT;#= namespaceName#>
{
<#
的foreach(表中无功表)
{
#>
///<总结>
///为<库接口;#= table.Name#>
///< /总结>
部分接口I<#= table.Name#>库:IRepository<<#= table.Name#>>
{
}

///<总结>
///为<库类;#= table.Name#>
///< /总结>
部分类<#= table.Name#>库:RepositoryBase<<#= table.Name#>>中I<#= table.Name#>库
{
}

///<总结> #= table.Name#>作为<
///波科类;
///< /总结>
部分类<#= table.Name#>
{
<#
的foreach(在table.Columns VAR列)
{
#>
&公众LT;#=证明(column.CsTypeName)#> <#=证明(column.Name)#> {搞定;组; }
<#
}
#>
}

///<总结> #= table.Name#>作为<
/// Command类;
///< /总结>
部分类<#= table.Name#>命令:CommandBase,ICommand的
{
<#
的foreach(在table.Columns VAR列)
{
#>
&公众LT;#=证明(column.CsTypeName)#> <#=证明(column.Name)#> {搞定;组; }
<#
}
#>
}

///<总结> #= table.Name#>作为<
///命令处理程序类;
///< /总结>
部分类<#= table.Name#> CommandHandler:ICommandHandler<<#= table.Name#>指挥与GT;
{
私人只读IUsersRepository _repository;
私人只读IUnitOfWork _unitOfWork;
&公众LT;#= table.Name#> CommandHandler(IUsersRepository库,IUnitOfWork的UnitOfWork)
{
_repository =库;
_unitOfWork =的UnitOfWork;
}

公共ICommandResult执行(小于#= table.Name#> Command命令)
{
<#= table.Name#>实体;

<#
VAR identityColumn = table.Columns.FirstOrDefault(C => c.IsIdentity);
如果(identityColumn == NULL)
{
#>
@@@ ERROR__NO_IDENTITY_COLUMN_FOUND_FOR:或其可#= table.FullName#>
<#
}
,否则
{
#>
如果(命令<#= identityColumn.Name#> == 0)
{
实体= AutoMapper.Mapper.Map<<#= table.Name#>> ;(命令);
_repository.Add(实体);
}
,否则
{
实体= _repository.Get(X => x.UserId ==命令<#= identityColumn.Name#>);
实体= AutoMapper.Mapper.Map<<#= table.Name#>>(命令);
_repository.Update(实体);
}
_unitOfWork.Commit(命令<#= identityColumn.Name#>);

返回新CommandResult(真实的,实体LT;#= identityColumn.Name#>);
<#
}
#>
}
}
<#
}
#>
}

<#+

使用静态架构的getSchema(字符串的connectionString)
{
(VAR连接=新的SqlConnection(的connectionString ))
{
connection.Open();

返回新的架构(连接);
}
}


#>



最后生成的代码看起来像这样(我的测试数据库,只有有一个表:CUS_Customer)

  // ######################### ################################################## #
// ##
//#--- ==> ŧH I S F我L E I S摹ê否E R A T E D< == - #
// ##
//#这意味着,当其#
//#再生的cs文件的任何修改都将丢失。改变应该代替被应用到相应的#
//#模板文件(.TT)#
// ##################### ################################################## #####











命名空间ModelGenerator
{
///<总结>
///库接口CUS_Customer
///< /总结>
部分接口ICUS_CustomerRepository:IRepository< CUS_Customer>
{
}

///<总结>
///库类CUS_Customer
///< /总结>
部分类CUS_CustomerRepository:RepositoryBase< CUS_Customer>中ICUS_CustomerRepository
{
}

///<总结>
///为CUS_Customer
///<波科类; /总结>
部分类CUS_Customer
{
公共System.Int64 CUS_ID {搞定;组; }
公共System.String CUS_FirstName {搞定;组; }
公共System.String CUS_LastName {搞定;组; }
公众的System.DateTime CUS_Born {搞定;组; }
公众的System.DateTime CUS_Created {搞定;组; }
}

///<总结>
///为CUS_Customer
///< Command类; /总结>
部分类CUS_CustomerCommand:CommandBase,ICommand的
{
公共System.Int64 CUS_ID {搞定;组; }
公共System.String CUS_FirstName {搞定;组; }
公共System.String CUS_LastName {搞定;组; }
公众的System.DateTime CUS_Born {搞定;组; }
公众的System.DateTime CUS_Created {搞定;组; }

}

///<总结>
///为CUS_Customer
///<命令处理程序类; /总结>
部分类CUS_CustomerCommandHandler:ICommandHandler< CUS_CustomerCommand>
{
私人只读IUsersRepository _repository;
私人只读IUnitOfWork _unitOfWork;
公共CUS_CustomerCommandHandler(IUsersRepository库,IUnitOfWork的UnitOfWork)
{
_repository =库;
_unitOfWork =的UnitOfWork;
}

公共ICommandResult执行(CUS_CustomerCommand命令)
{
CUS_Customer实体;

如果(command.CUS_ID == 0)
{
实体= AutoMapper.Mapper.Map< CUS_Customer>(命令);
_repository.Add(实体);
}
,否则
{
实体= _repository.Get(X => x.UserId == command.CUS_ID);
实体= AutoMapper.Mapper.Map< CUS_Customer>(命令);
_repository.Update(实体);
}
_unitOfWork.Commit(command.CUS_ID);

返回新CommandResult(真,entity.CUS_ID);
}
}
}

如果你拉从项目GitHub上并更新连接字符串的东西是相关的,你应该生成代码为您服务。如果您遇到任何问题,只是回复这个帖子。


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. (i dont use db migrations)
  3. Create a POCO model that matches the EF class created in #2.
  4. Create repository class
  5. Create Commands and Handlers for CQRS pattern
  6. Create AutoMapper maps for the newly created classes

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. That got me thinking that I could somehow use those templates (new ones) to generate all the standard support items for basic CRUD operations. 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)

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

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

The template itself use T4Include.Schema to get the db 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/).

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)

// ############################################################################
// #                                                                          #
// #        ---==>  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. If you run into any issues just respond to this post.

这篇关于使用T4模板的基础上POCO生成多个班的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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