前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >创建代码生成器可以很简单:如何通过T4模板生成代码?[上篇]

创建代码生成器可以很简单:如何通过T4模板生成代码?[上篇]

作者头像
蒋金楠
发布于 2018-02-08 06:55:54
发布于 2018-02-08 06:55:54
3.7K0
举报
文章被收录于专栏:大内老A大内老A

在《基于T4的代码生成方式》中,我对T4模板的组成结构、语法,以及T4引擎的工作原理进行了大体的介绍,并且编写了一个T4模板实现了如何将一个XML转变成C#代码。为了让由此需求的读者对T4有更深的了解,我们通过T4来做一些更加实际的事情——SQL Generator。在这里,我们可以通过SQL Generator为某个数据表自动生成进行插入、修改和删除的存储过程。[文中源代码从这里下载]

一、代码生成器的最终使用效果

我们首先来看看通过直接适用我们基于T4的SQL生成模板达到的效果。右图(点击看大图)是VS2010的Solution Explorer,在Script目录下面,我定义了三个后缀名为.tt的T4模板。它们实际上是基于同一个数据表(T_PRODUCT)的三个存储过程的生成创建的模板文件,其中P_PRODUCT_D.tt、P_PRODUCT_I.tt和P_PRODUCT_D.tt分别用于记录的删除、插入和修改。自动生成的扩展名为.sql的同名附属文件就是相应的存储过程。

基于三种不同的数据操作(Insert、Update和Delete),我创建了3个重用的、与具体数据表无关的模板: InsertProcedureTemplate、UpdateProcedureTemplate和DeleteProcedureTemplate。这样做的目的为为了实现最大的重用,如果我们需要为某个数据表创建相应的存储过程的时候,我们可以直接使用它们传入相应的数据表名就可以了。实际上,P_PRODUCT_D.tt、P_PRODUCT_I.tt和P_PRODUCT_D.tt这三个T4模板的结构很简单,它们通过<#@include>指令将定义着相应ProcedureTemplate的T4模板文件包含进来。最终的存储过程脚本通过调用ProcudureTempalte的Render方法生成。其中构造函数的参数表示的分别是连接字符串名称(在配置文件中定义)和数据表的名称。

代码语言:js
AI代码解释
复制
<#@ template language="C#" hostspecific="True" #>
<#@ output extension="sql" #>
<#@ include file="T4Toolbox.tt" #>
<#@ include file="..\Templates\DeleteProcedureTemplate.tt" #>
<#
    new DeleteProcedureTemplate("TestDb","T_PRODUCT").Render();
#>
<#@ template language="C#" hostspecific="True" #>
<#@ output extension="sql" #>
<#@ include file="T4Toolbox.tt" #>
<#@ include file="..\Templates\InsertProcedureTemplate.tt" #>
<#
    new InsertProcedureTemplate("TestDb","T_PRODUCT").Render();
#>
<#@ template language="C#" hostspecific="True" #>
<#@ output extension="sql" #>
<#@ include file="T4Toolbox.tt" #>
<#@ include file="..\Templates\UpdateProcedureTemplate.tt" #>
<#
    new UpdateProcedureTemplate("TestDb","T_PRODUCT").Render();
#>

二、安装T4工具箱(ToolBox)和编辑器

VS本身只提供一套基于T4引擎的代码生成的执行环境,为了利于你的编程你可以安装一些辅助性的东西。T4 ToolBox是一个CodePlex上开源的工具,它包含一些可以直接使用的代码生成器,比如Enum SQL ViewAzMan wrapperLINQ to SQL classesLINQ to SQL schemaEntity Framework DAL等。T4 ToolBox还提供一些基于T4方面的VS的扩展。当你按照之后,在“Add New Item”对话框中就会多出一个命名为“Code Generation”的类别,其中包括若干文件模板。下面提供的T4模板的编辑工作依赖于这个工具。

为了提高编程体验,比如智能感知以及代码配色,我们还可以安装一些第三方的T4编辑器。我使用的是一个叫做Oleg Sych的T4 Editor。它具有免费版本和需要付费的专业版本,当然我使用的免费的那款。成功按装了,它也会在Add New Item”对话框中提供相应的基于T4 的文件模板。

三、创建数据表

T4模板就是输入和输出的一个适配器,这与XSLT的作用比较类似。对于我们将要实现的SQL Generator来说,输入的是数据表的结构(Schema)输出的是最终生成的存储过程的SQL脚本。对于数据表的定义,不同的项目具有不同标准。我采用的是我们自己的数据库标准定义的数据表:T_PRODUCT(表示产品信息),下面是创建表的脚本。

代码语言:js
AI代码解释
复制
CREATE TABLE [dbo].[T_PRODUCT](
    [ID]                [VARCHAR](50) NOT NULL,
    [NAME]              [NVARCHAR] NOT NULL,
    [PRICE]             [float] NOT NULL,
    [TOTAL_PRICE]       [FLOAT] NOT NULL,
    [DESC]              [NVARCHAR]  NULL,

    [CREATED_BY]        [VARCHAR](50) NULL,
    [CREATED_ON]        [DATETIME] NULL,
    [LAST_UPDATED_BY]   [VARCHAR](50) NULL,
    [LAST_UPDATED_ON]   [DATETIME] NULL,
    [VERSION_NO]        [TIMESTAMP] NULL,
    [TRANSACTION_ID]    [VARCHAR](50) NULL,
 CONSTRAINT [PK_T_PRODUCT] PRIMARY KEY CLUSTERED( [ID] ASC)ON [PRIMARY])

每一个表中有6个公共的字段:CREATED_BY、CREATED_ON、LAST_UPDATED_BY、LAST_UPDATED_ON、VERSION_NO和TRANSACTION_ID分别表示记录的创建者、创建时间、最新更新者、最新更新时间、版本号(并发控制)和事务ID。

四、创建抽象的模板:ProcedureTemplate

我们需要为三不同的数据操作得存储过程定义不同的模板,但是对于这三种存储过程的SQL结构都是一样的,基本结果可以通过下面的SQL脚本表示。

代码语言:js
AI代码解释
复制
IF OBJECT_ID( '<<ProcedureName>>', 'P' ) IS NOT NULL
    DROP  PROCEDURE  <<ProcedureName>>
GO

CREATE PROCEDURE <<ProcedureName>>
(
    <<ParameterList>>
)
AS

    <<ProcedureBody>>

GO

为此我定义了一个抽象的模板:ProcedureTemplate。为了表示CUD三种不同的操作,我通过T4模板的“类特性块”(Class Feature Block)定义了如下一个OperationKind的枚举。

代码语言:js
AI代码解释
复制
<#+ 
    public enum OperationKind
    {
        Insert,
        Update,
        Delete
    }
#>

然后下面就是整个ProcedureTemplate的定义了。ProcedureTemplate直接继承自T4Toolbox.Template(来源于T4 ToolBox,它继承自TextTransformation)。ProcedureTemplate通过SMOSQL Server Management Object)获取数据表的结构(Schema)信息,所以我们需要应用SMO相关的程序集和导入相关命名空间。ProcedureTemplate具有两个属性Table(SMO中表示数据表)和OperationKind(表示具体的CUD操作的一种),它们均通过构造函数初始化。简单起见,我们没有指定Server,而默认采用本机指定的数据库。

代码语言:js
AI代码解释
复制
   1: <#@ assembly name="Microsoft.SqlServer.ConnectionInfo" #>
   2: <#@ assembly name="Microsoft.SqlServer.Smo" #>
   3: <#@ assembly name="Microsoft.SqlServer.Management.Sdk.Sfc" #>
   4: <#@ import namespace="System" #>
   5: <#@ import namespace="Microsoft.SqlServer.Management.Smo" #>
   6: <#+
   7: public abstract class ProcedureTemplate : Template
   8: {
   9:     public OperationKind OperationKind {get; private set;}
  10:     public Table Table {get; private set;}
  11:     
  12:     public const string VersionNoField             = "VERSION_NO";
  13:     public const string VersionNoParameterName     = "@p_version_no";
  14:     
  15:     public ProcedureTemplate(string databaseName, string tableName,OperationKind operationKind)
  16:     {
  17:         this.OperationKind     = operationKind;
  18:         Server server = new Server();
  19:         Database database = new Database(server,databaseName);
  20:         this.Table = new Table(database, tableName);
  21:         this.Table.Refresh();
  22:     }
  23:     
  24:     public virtual string GetProcedureName()
  25:     {
  26:         switch(this.OperationKind)
  27:         {
  28:             case OperationKind.Insert:    return "P_" +this.Table.Name.Remove(0,2) + "_I";
  29:             case OperationKind.Update:    return "P_" +this.Table.Name.Remove(0,2) + "_U";
  30:             default:                    return "P_" +this.Table.Name.Remove(0,2) + "_D";
  31:         }        
  32:     }
  33:     
  34:     protected virtual string GetParameterName(string columnName)
  35:     {
  36:         return "@p_" + columnName.ToLower();
  37:     }
  38:     
  39:     protected abstract void RenderParameterList();
  40:     
  41:     protected abstract void RenderProcedureBody();        
  42:  
  43:     public override string TransformText()
  44:     {
  45: #>
  46: IF OBJECT_ID( '[dbo].[<#=  GetProcedureName()#>]', 'P' ) IS NOT NULL
  47:     DROP  PROCEDURE  [dbo].[<#=  GetProcedureName()#>]
  48: GO
  49:  
  50: CREATE PROCEDURE [dbo].[<#= GetProcedureName() #>]
  51: (
  52: <#+
  53:         PushIndent("\t");
  54:         this.RenderParameterList();
  55:         PopIndent();
  56: #>
  57: )
  58: AS
  59:    
  60: <#+
  61:         PushIndent("\t");
  62:         this.RenderProcedureBody();
  63:         PopIndent(); 
  64:         PopIndent(); 
  65:         WriteLine("\nGO");
  66:         return this.GenerationEnvironment.ToString();
  67:     }
  68: }
  69: #>

存储过程的参数我们采用小写形式,直接在列名前加上一个"p_”(Parameter)前缀,列名到参数名之间的转化通过方法GetParameterName实现。存储过程名称通过表明转化,转化规则为:将"T_”(Table)改成"P_”(Procedure)前缀,并添加"_I"、"_U"和"_D"表示相应的操作类型,存储过程名称的解析通过GetProcedureName实现。整个存储过程的输出通过方法TransformText输出,并通过PushIndent和PopIndent方法控制缩进。由于CUD存储只有两个地方不一致:参数列表和存储过程的主体,我定义了两个抽象方法RenderParameterList和RenderProcedureBody让具体的ProcedureTemplate去实现。

五、为CUD操作创建具体模板

基类ProcedureTemplate已经定义出了主要的转化规则,我们现在需要做的就是通过T4模板创建3个具体的ProcedureTemplate,分别实现针对CUD存储过程的生成。为此我创建了三个继承自ProcedureTemplate的具体类:InsertProcedureTemplate、UpdateProcedureTemplate和DeleteProcedureTemplate,它只需要实现RenderParameterList和RenderProcedureBody这两个抽象方法既即可,下面是它们的定义。

代码语言:js
AI代码解释
复制
<#@ include file="ProcedureTemplate.tt" #>
<#+
public class InsertProcedureTemplate : ProcedureTemplate
{   
    public InsertProcedureTemplate(string databaseName, string tableName): base(databaseName,tableName,OperationKind.Insert){}

    protected override void RenderParameterList()
    {
        for(int i=0; i<this.Table.Columns.Count;i++)
        {
            Column column = this.Table.Columns[i];
            if(column.Name != VersionNoField)
            {
                if(i<this.Table.Columns.Count -1)
                {
                    WriteLine("{0, -20}[{1}],", GetParameterName(column.Name),column.DataType.Name.ToUpper());
                }
                else
                {
                    WriteLine("{0, -20}[{1}]", GetParameterName(column.Name),column.DataType.Name.ToUpper());
                }
            }            
        }    
    }

    protected override void RenderProcedureBody()
    {
        WriteLine("INSERT INTO [dbo].[{0}]", this.Table.Name);
        WriteLine("(");
        PushIndent("\t");
        for(int i=0; i<this.Table.Columns.Count;i++)
        {
            Column column = this.Table.Columns[i];
            if(column.Name != VersionNoField)
            {
                if(i<this.Table.Columns.Count -1)
                {
                    WriteLine("[" +column.Name + "],");    
                }
                else
                {
                    WriteLine("[" +column.Name + "]");    
                }
            }
        }
        PopIndent();
        WriteLine(")");
        WriteLine("VALUES");
        WriteLine("(");
        PushIndent("\t");
        for(int i=0; i<this.Table.Columns.Count;i++)
        {
            Column column = this.Table.Columns[i];
            if(column.Name != VersionNoField)
            {
                if(i<this.Table.Columns.Count -1)
                {
                    WriteLine(GetParameterName(column.Name) + ",");    
                }
                else
                {
                    WriteLine(GetParameterName(column.Name));    
                }
            }

        }
        PopIndent();
        WriteLine(")");
    }
}
#>
<#@ include file="ProcedureTemplate.tt" #>
<#+
public class UpdateProcedureTemplate : ProcedureTemplate
{   
    public UpdateProcedureTemplate(string databaseName, string tableName): base(databaseName,tableName,OperationKind.Update)
    {}

    protected override void RenderParameterList()
    {
        for(int i=0; i<this.Table.Columns.Count;i++)
        {
            Column column = this.Table.Columns[i];
            if(i<this.Table.Columns.Count -1)
            {
                 WriteLine("{0, -20}[{1}],", GetParameterName(column.Name),column.DataType.Name.ToUpper());
            }
            else
            {
                 WriteLine("{0, -20}[{1}]", GetParameterName(column.Name),column.DataType.Name.ToUpper());
            }
        }    
    }

    protected override void RenderProcedureBody()
    {
        WriteLine("UPDATE [dbo].[{0}]", this.Table.Name);
        WriteLine("SET");
        PushIndent("\t");
        for(int i=0; i<this.Table.Columns.Count;i++)
        {
            Column column = this.Table.Columns[i];
            if(!column.InPrimaryKey)
            {
                if(i<this.Table.Columns.Count -1)
                {
                    WriteLine("{0,-20}= {1},", "[" +column.Name + "]", this.GetParameterName(column.Name));    
                }
                else
                {
                    WriteLine("{0,-20}= {1}", "[" +column.Name+"]", this.GetParameterName(column.Name));    
                }
            }            
        }
        PopIndent();
        WriteLine("WHERE");
        PushIndent("\t");
        for(int i=0; i<this.Table.Columns.Count;i++)
        {
            Column column = this.Table.Columns[i];
            if(column.InPrimaryKey)
            {
                WriteLine("{0, -20}= {1} AND", "[" +column.Name + "]", GetParameterName(column.Name));
            }                        
        }
        WriteLine("{0, -20}= {1}", "[" + VersionNoField + "]", VersionNoParameterName);
        PopIndent();
    }
}
#>
<#@ include file="ProcedureTemplate.tt" #>
<#+
public class DeleteProcedureTemplate : ProcedureTemplate
{   
    public DeleteProcedureTemplate(string databaseName, string tableName): base(databaseName,tableName,OperationKind.Delete){}

    protected override void RenderParameterList()
    {
        foreach (Column column in this.Table.Columns)
        {
            if (column.InPrimaryKey)
            {
                WriteLine("{0, -20}[{1}],", GetParameterName(column.Name),column.DataType.Name.ToUpper());
            }
        }
        WriteLine("{0, -20}[{1}]", VersionNoParameterName, "TIMESTAMP");
    }

    protected override void RenderProcedureBody()
    {
        WriteLine("DELETE FROM [dbo].[{0}]", this.Table.Name);
        WriteLine("WHERE");
        PushIndent("\t\t");
        foreach (Column column in this.Table.Columns)
        {
            if (column.InPrimaryKey)
            {
                WriteLine("{0, -20}= {1} AND", column.Name, GetParameterName(column.Name));
            }
        }
        WriteLine("{0, -20}= {1}", VersionNoField, VersionNoParameterName);            
    }
}
#>

至于三个具体的ProcedureTemplate如何生成参数列表和主体部分,在这里就不在多做说明了。这里唯一需要强调的是:脚本的输出是通过TextTransformation的静态WriteLine方法实现,它和Console的同名方法使用一致。针对我们之前定义的数据表T_PRODUCT的结果,通过在文章开头定义的三个TT模板,最终将会生成如下的三个存储过程。

代码语言:js
AI代码解释
复制
IF OBJECT_ID( '[dbo].[P_PRODUCT_I]', 'P' ) IS NOT NULL
    DROP  PROCEDURE  [dbo].[P_PRODUCT_I]
GO

CREATE PROCEDURE [dbo].[P_PRODUCT_I]
(
    @p_id               [VARCHAR],
    @p_name             [NVARCHAR],
    @p_price            [FLOAT],
    @p_total_price      [FLOAT],
    @p_desc             [NVARCHAR],
    @p_created_by       [VARCHAR],
    @p_created_on       [DATETIME],
    @p_last_updated_by  [VARCHAR],
    @p_last_updated_on  [DATETIME],
    @p_transaction_id   [VARCHAR]
)
AS

    INSERT INTO [dbo].[T_PRODUCT]
    (
        [ID],
        [NAME],
        [PRICE],
        [TOTAL_PRICE],
        [DESC],
        [CREATED_BY],
        [CREATED_ON],
        [LAST_UPDATED_BY],
        [LAST_UPDATED_ON],
        [TRANSACTION_ID]
    )
    VALUES
    (
        @p_id,
        @p_name,
        @p_price,
        @p_total_price,
        @p_desc,
        @p_created_by,
        @p_created_on,
        @p_last_updated_by,
        @p_last_updated_on,
        @p_transaction_id
    )

GO
IF OBJECT_ID( '[dbo].[P_PRODUCT_U]', 'P' ) IS NOT NULL
    DROP  PROCEDURE  [dbo].[P_PRODUCT_U]
GO

CREATE PROCEDURE [dbo].[P_PRODUCT_U]
(
    @p_id               [VARCHAR],
    @p_name             [NVARCHAR],
    @p_price            [FLOAT],
    @p_total_price      [FLOAT],
    @p_desc             [NVARCHAR],
    @p_created_by       [VARCHAR],
    @p_created_on       [DATETIME],
    @p_last_updated_by  [VARCHAR],
    @p_last_updated_on  [DATETIME],
    @p_version_no       [TIMESTAMP],
    @p_transaction_id   [VARCHAR]
)
AS

    UPDATE [dbo].[T_PRODUCT]
    SET
        [NAME]              = @p_name,
        [PRICE]             = @p_price,
        [TOTAL_PRICE]       = @p_total_price,
        [DESC]              = @p_desc,
        [CREATED_BY]        = @p_created_by,
        [CREATED_ON]        = @p_created_on,
        [LAST_UPDATED_BY]   = @p_last_updated_by,
        [LAST_UPDATED_ON]   = @p_last_updated_on,
        [VERSION_NO]        = @p_version_no,
        [TRANSACTION_ID]    = @p_transaction_id
    WHERE
        [ID]                = @p_id AND
        [VERSION_NO]        = @p_version_no

GO
IF OBJECT_ID( '[dbo].[P_PRODUCT_D]', 'P' ) IS NOT NULL
    DROP  PROCEDURE  [dbo].[P_PRODUCT_D]
GO

CREATE PROCEDURE [dbo].[P_PRODUCT_D]
(
    @p_id               [VARCHAR],
    @p_version_no       [TIMESTAMP]
)
AS

    DELETE FROM [dbo].[T_PRODUCT]
    WHERE
            ID                  = @p_id AND
            VERSION_NO          = @p_version_no

GO

六、局限性

上面这个例子虽然很好实现了基于数据表的存储过程的生成,但是使用起来仍然不方便——我们需要为每一个需要生成出来的存储过程定义T4模板。也就是说在这种代码生成下,模板文件和生成文件之间是1:1的关系。实际上我们希望的方式是:创建一个基于某个表的TT文件,让它生成3个CUD三个存储过程;或者在一个TT文件中设置一个数据表的列表,让基于这些表的所有存储过程一并生成;或者直接子指定数据库,让所有数据表的存储过程一并生成出来。到底如何实现基于多文件的代码生成,请听《下回》分解。

从数据到代码——通过代码生成机制实现强类型编程[上篇] 从数据到代码——通过代码生成机制实现强类型编程[下篇] 从数据到代码——基于T4的代码生成方式 创建代码生成器可以很简单:如何通过T4模板生成代码?[上篇] 创建代码生成器可以很简单:如何通过T4模板生成代码?[下篇]

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2010-10-25 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
编写T4模板进行代码生成无法避免的两个话题:"Assembly Locking"&"Debug"
在这之前,我写了一系列关于代码生成和T4相关的文章,而我现在也试图将T4引入我们自己的开发框架。在实践中遇到了一些问题,也解决了不少问题。如果你也在进行T4相关的开发,相信你也一定会遇到这些问题。为此,特意将这些问题和解决方案与朋友们分享,希望在遇到这些问题的时候少走弯路。本篇文章介绍的是两个重要的话题:程序集锁定和调试。 目录 一、程序集引用导致的编译问题 二、T4引擎对引用程序集的锁定 三、Debugger.Break导致VS 2010的Crash
蒋金楠
2018/02/07
9760
编写T4模板进行代码生成无法避免的两个话题:"Assembly Locking"&"Debug"
从数据到代码——基于T4的代码生成方式
在之前写一篇文章《从数据到代码》(上篇、下篇)中,我通过基于CodeDOM+Custom Tool的代码生成方式实现了将一个XML表示的消息列表转换成了相应的C#代码,从而达到了强类型编程的目的。实际上,我们最常用的代码生成当时不是CodeDOM,而是T4,这是一个更为强大,并且适用范围更广的代码生成技术。今天,我将相同的例子通过T4的方式再实现一次,希望为那些对T4不了解的读者带来一些启示。同时这篇文章将作为后续文章的引子,在此之后,我将通过两篇文章通过具体实例的形式讲述如果在项目将T4为我所用,以达到提
蒋金楠
2018/02/07
2.1K0
从数据到代码——基于T4的代码生成方式
Audit Logging-Stored Procedure
1. T_ORDER For Insert: sp_order_i IF EXISTS (SELECT * FROM sysobjects WHERE type = 'P' AND name = 'sp_order_i')     BEGIN         DROP  Procedure  sp_order_i     END GO CREATE Procedure sp_order_i     (         @p_order_id INT OUTPUT,         @p_order_da
蒋金楠
2018/01/16
6270
Razor Engine,实现代码生成器的又一件利器
Razor Engine,之前仅仅是ASP.NET MVC的一种View引擎,目前已经完全成为一种可以独立使用的模版引擎,并且已经成为了CodePlex上一个开源的项目(http://razorengine.codeplex.com/)。对于使用过ASP.NET MVC Razor视图引擎的朋友们一定已经领略过它的灵活性和易用性,在这篇文章中我们将利用它来实现一个代码生成器使我们可以以Razor的语法来定义代码模版。[源代码从这里下载] 在《一个简易版的T4代码生成"框架"》这篇文章中,我创建了一个能够
蒋金楠
2018/01/15
1.8K0
Razor Engine,实现代码生成器的又一件利器
欢迎使用开源的代码生成器Code-Builder
本来code-builder是专门为MyBatis Enhance来编写的一块代码生成器,不过仅仅使用到Enhance却没有什么新鲜感,所以把生成这块分离出来提供给大家使用,希望可以对提高项目研发效率提供一些帮助。
恒宇少年
2018/08/13
9890
JAVA实现编写平台代码生成器
[项目中经常写CRUD,但实际这些工作,我觉得如果有一个完整的代码规范,完全可以自动生成,加快开发效率. 代码生成器技术原理不复杂,一般就是写好一个模板生成一系列的代码而已。我看到mybatis_plus的代码生成器就相当不错,就自己拿过来改造了一下 1.项目中,需先引入vm库,用来生成代码
星痕
2018/09/12
2.7K1
快速学习-代码生成器搭建环境
4 代码生成器搭建环境 4.1 思路分析 工具的执行逻辑如下图所示: 如上分析,得知完成代码生成器需要以下几个操作: 用户填写的数据库信息,工程搭建信息需要构造到实体类对象中方便操作 数据库表
cwl_java
2020/02/11
2760
自定义t4模版,根据数据库生成实体模型
http://www.cnblogs.com/artech/archive/2010/11/17/CodeGeneration.html
liulun
2022/05/09
3130
创建代码生成器可以很简单:如何通过T4模板生成代码?[下篇]
在《上篇》中我们通过T4模板为我们指定的数据表成功生成了我们需要的用于添加、修改和删除操作的存储过程。但是这是一种基于单个文件的解决方案,即我们必须为每一个生成的存储过程建立一个模板。如果我们提供一种基于多文件的代码生成方式,将会为编程人员带来极大的便利。借助于T4 ToolBox这个开源工具箱,多文件的SQL Generator的实现变得异常简单。[文中的例子可以从这里下载] 目录 一、多文件代码生成器会带来多大的便利? 二、创建自定义的Generator 三、ProcedureGenerator
蒋金楠
2018/02/08
9110
创建代码生成器可以很简单:如何通过T4模板生成代码?[下篇]
代码生成新选择-T4模板引擎
在博客堂看到ASP.NET MVC中的T4模板, 之前我也写过一篇文本模板转换工具箱T4。 T4(Text Template Transformation Toolkit)则是微软官方在VisualStudio 2008中开始使用的代码生成引擎,可惜T4不像微软公布的别的工具那样参考资料充足,而且模板也很少,MSDN上甚至没有一个专门的目录用来介绍它,惟一沾边的就是在介绍DSL工具时带上的Generating Artifacts By Using Text Templates。 Visual Web Dev
张善友
2018/01/31
9720
2020-3-3-使用T4模板进行C#代码生成
有过前端开发经验的同学一定了解模板文件的重要用户。其实C#也有类似的模板功能(T4模板),不仅可以生成html文件,还可以生成代码。今天就给大家介绍一下。
黄腾霄
2020/06/10
3.1K0
一键生成前后端代码,Mybatis-Plus代码生成器让我舒服了
在日常的软件开发中,程序员往往需要花费大量的时间写CRUD,不仅枯燥效率低,而且每个人的代码风格不统一。MyBatis-Plus 代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块及前端页面的代码,极大的提升了开发效率。
不会飞的小鸟
2020/07/31
4.2K0
MybatisPlus——全网配置最全的代码生成器
官方文档:https://baomidou.com/(建议多看看官方文档,每种功能里面都有讲解)
不吃紫菜
2022/09/23
3.5K0
MybatisPlus——全网配置最全的代码生成器
go模板-代码生成器
能用程序去做的事,就不要用手,编写自己的代码生成器就是用来解放你的双手,替你做一些重复性的工作。 上篇帖子写了模板的基础 go模板详说 ,有了基础就要做点什么东西,把所学到的东西应用起来才能更好的进步。于是用模板写了一个代码生成器,用于把数据库的表转换成go的struct,目前支持MySQL和PostgreSQL。这篇帖子写实现的思路和一些具体的代码实现。 Github地址: yggdrasill 看一下效果
lpxxn
2020/05/29
1.1K0
在Entity Framework中使用存储过程(一):实现存储过程的自动映射
之前给自己放了一个比较长的假期,在这期间基本上没怎么来园子逛。很多朋友的留言也没有一一回复,在这里先向大家道个歉。最近一段时间的工作任务是如何将ADO.NET Entity Framework 4.0(以下简称EF)引入到我们的开发框架,进行相应的封装、扩展,使之成为一个符合在特定场景下进行企业级快速开发的ORM。在此过程中遇到了一些挑战,也有一些心得。为了向大家分享这些心得,也为了借助大家的脑袋解决我们遇到的问题,接下来我会写一系列相关的文章。这些文章的读者适合那些对EF有基本了解的人。 第一个主题是关于
蒋金楠
2018/02/07
2.6K0
模版引擎XTemplate与代码生成器XCoder(源码)
模版引擎XTemplate是一个仿T4设计的引擎,功能上基本与T4一致(模版语法上完全兼容T4,模版头指令部分兼容)。     自己设计模版引擎,就是为了代码生成器、网站模版、邮件模版等多种场合,也就是要能拿出来单独使用、功能强大并且容易控制的。T4是个很好的引擎,但是它的设计基本上倾向于vs,几乎不顾别的场合。     XTemplate特点如下:     1,完全使用C#作为模版语言。跟ASP、ASP.Net页面的解析一样,把<##>标签外的文本内容当作字符串,用一个StringBuilder,标签内
大石头
2018/01/15
9120
模版引擎XTemplate与代码生成器XCoder(源码)
工欲善其事,必先利其器:分享一套Code Smith 搭建N层架构模板
 开篇 平常开发时,由于冗余代码过多,程序员做重复的工作过多势必会影响开发效率。倘若对重复性代码简单的复制、粘贴,虽然也能节省时间,但也需仔细一步步替换,这无疑也是一件费力的事。这时我们急需代码生成工具,根据一套Template快速生成我们需要的代码。代码生成器原理简单,完全可以开发一套适合自己的代码生成器,一个最简单的代码生成器,有几点你需要关注下: 查询系统视图:INFORMATION_SCHEMA.TABLES、 INFORMATION_SCHEMA.COLUMNS  可以获得数据库中表、列的相
用户1161731
2018/01/11
1.3K0
工欲善其事,必先利其器:分享一套Code Smith 搭建N层架构模板
WCF版的PetShop之二:模块中的层次划分[提供源代码下载]
上一篇文章主要讨论的是PetShop的模块划分,在这一篇文章中我们来讨论在一个模块中如何进行层次划分。模块划分应该是基于功能的,一个模块可以看成是服务于某项功能的所有资源的集合;层次划分侧重于关注点分离(SoC:Separation of Concern ),让某一层专注于某项单一的操作,以实现重用性、可维护性、可测试性等相应的目的。Source Code从这里下载。 一、基本的层次结构 我们接下来将目光聚焦到模块内部,看看每一个模块具体又有怎样的层次划分。我们将Infrastructures、Produc
蒋金楠
2018/01/16
1.3K0
WCF版的PetShop之二:模块中的层次划分[提供源代码下载]
代码生成器原理及示例
在三层架构中Model、DAL(Data Access Layer)、BLL层有必要分开,其中有些代码可以由代码生成器生成。虽然网络已经有成熟的代码生成器,但是第三方代码生成器在实际应用场景中,生成的代码经常还需要在其基础上修改。修改其代码就不如修改代码生成器本身。所以掌握代码生成器的编写方法、原理还是很有必要的。
全栈程序员站长
2022/07/25
9900
代码生成器原理及示例
简单代码生成器原理剖析(一)
上篇文章(深入浅出三层架构)分析了简单三层架构的实现。包括Model,DAL(数据访问层),BLL(业务逻辑层)的实现。 实际开发中,由于重复代码的操作,会花费大量时间,如果以代码生成器来自动生成三层
用户1161731
2018/01/11
1.4K0
简单代码生成器原理剖析(一)
推荐阅读
相关推荐
编写T4模板进行代码生成无法避免的两个话题:"Assembly Locking"&"Debug"
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文