• T4学习- 4、Kalman Studio-T4代码生成器


    一、简介

    开源代码生成器-Kalman Studio

    https://github.com/loamen/Kalman.Studio

    image

    1、软件主要功能如下:

    1、基于T4的代码生成工具,根据数据库元数据信息生成代码,支持多数据库,支持批量代码生成;
    2、支持根据PowerDesigner物理模型文件来生成代码;
    3、内置了一个简单的文本编辑器,支持代码高亮显示;
    4、数据库元数据信息浏览工具;
    5、数据库文档生成工具,支持输出word及pdf文件格式;
    6、IIS日志解析器,小网站可以用用;
    7、其他工具,字符串相关操作等。
    

    二、编写T4模板:

    1、VS自动根据模板自动生成代码

    首先,打开Visual Studio,新建一个文本文件,将扩展名改为"tt"
    o_new[1]

    这时Visual Studio会为Entity.tt生成一个对应的类文件Entity.cs。这是因为Visual Studio内置了一个代码生成工具“TextTemplatingFileGenerator”,会自动为每个模板文件生成对应的类文件,如果你在Entity.tt中编辑好模板,然后打开Entity.cs,TextTemplatingFileGenerator会自动解析模板,将代码输出到文件Entity.cs。

    o_TextTemplatingFileGenerator[1]

    2、编写T4模板

    我们这里不需要使用TextTemplatingFileGenerator生成代码,把属性面板,“自定义工具”里面的文字“TextTemplatingFileGenerator”删掉,对应的类文件会自动删除;然后可以开始编写模板了。

    我这里先展示一个编写好的实体模板,然后再详细说明。

    <#@ template language="C#v3.5" hostSpecific="true" debug="true" #>
    <#@ output extension=".cs" #>
    <# 
        TableHost host = (TableHost)(Host); 
        SOTable table = host.Table;
        List<SOColumn> list = host.ColumnList;
        string columnPrefix = host.GetString("ColumnPrefix");
        int prefixLevel = host.GetInt32("PrefixLevel");
        string nameSpace = host.GetString("NameSpace");
        string className = host.GetString("ClassName");
        if(string.IsNullOrEmpty(nameSpace))nameSpace = "Entity";
        if(string.IsNullOrEmpty(className))className = table.Name;
    #>
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Data;
    
    namespace <#= nameSpace #>
    {
        /// <summary>
        /// <#= table.Comment == "" ? table.Name : table.Comment #>
        /// </summary>
        [Serializable]
        public partial class <#= className #>
        {
            <# foreach (SOColumn c in list)
            { #>/// <summary>
            /// <#= c.Comment == "" ? c.Name : c.Comment #>
            /// </summary>
            public <#= TypeUtil.DbType2TypeString(c.DataType) #> <#= StringUtil.RemovePrefix(c.Name, columnPrefix, prefixLevel).Replace(" ", "") #> { get; set; }
            
            <# } #>
            
        }
    }

    3、T4模板语法

    • <#@ template language="C#v3.5" hostSpecific="true" debug="true" #>:可以指定模板使用的语言,hostSpecific="true"表示是否使用特定的host(Kalman Studio里面使用的是TableHost对象,必须实现接口ITextTemplatingEngineHost)。
    • <#@ output extension=".cs" #> : 指定生成文件的扩展名。
    • <#@ assembly name="System.Data" #>:添加程序集引用,如果要使用第三方程序集,那么最好在项目中添加引用,或者加入到GAC。
    • <#@ import namespace="System.Data" #>:导入要使用的命名空间,注意:这里的命名空间必须要在前面指定的程序集里面找得到的,比如我指定命名空间"System.Data","System.Data.Common",这些在程序集System.Data中都有的。
    • <#@ include file="test.tt" #> 导入模板,类似Html的include用法
    • <#   #>:定义代码块
    • <#= #>:定义表达式
    • <#+ #>:定义变量

    三、Kalman Studio改进

    1、自定义架构对象SchemaObject下的类。

    2、自定义T4模板的引擎主机类:T4TemplatingEngineHost

    3、自定义SqlServerSchema

    image

    更改Kalman项目的SqlServerSchema文件,增加Computed是否是计算字段的判断。

     public override List<SOColumn> GetTableColumnList(SOTable table)
            {
                string cmdText = string.Format(@"use [{2}];select   colm.name column_name, object_definition(colm.default_object_id) as column_def, systype.name type_name, colm.is_identity, colm.is_nullable ,
                                                            cast(colm.max_length as int) length, cast(colm.precision as int) precision, cast(colm.scale as int) scale, colm.is_computed
                                                from     sys.columns colm
                                                    inner join sys.types systype on colm.system_type_id = systype.system_type_id and colm.user_type_id = systype.user_type_id
                                                where    colm.object_id = object_id('{0}')
                                                order by colm.column_id;", table.Name, table.Owner, table.Database.Name);
    
                List<SOColumn> columnList = new List<SOColumn>();
                List<string> pkList = GetPrimaryKeys(table);
                DataTable dt = this.DbProvider.ExecuteDataSet(System.Data.CommandType.Text, cmdText).Tables[0];
    
                foreach (DataRow row in dt.Rows)
                {
                    SOColumn column = new SOColumn
                    {
                        Parent = table,
                        Name = row["column_name"].ToString(),
                        DefaultValue = row["column_def"].ToString(),
                        Nullable = row["is_nullable"].ToString()== "True",
                        NativeType = row["type_name"].ToString(),
                        Identify = row["is_identity"].ToString() == "True",
                        Computed = row["is_computed"].ToString() == "True",
                        //ForeignKey
                        Length = ConvertUtil.ToInt32(row["length"], -1),
                        Precision = ConvertUtil.ToInt32(row["precision"], -1),
                        Scale = ConvertUtil.ToInt32(row["scale"], –1),
                    };
    
                    column.PrimaryKey = pkList.Contains(column.Name);
                    column.DataType = this.GetDbType(column.NativeType);
                    column.Comment = GetColumnComment(column);
                    columnList.Add(column);
                }
    
                return columnList;
            }
    View Code

    4、常用的几个自定义的T4模板

    1、生成实体:model.tt

    <#@ template language="C#v3.5" hostSpecific="true" debug="true" #>
    <#@ output extension=".cs" #>
    <# 
        TableHost host = (TableHost)(Host); 
        SOTable table = host.Table;
        List<SOColumn> list = host.ColumnList;
        string nameSpace = host.GetString("NameSpace");
        string className = host.GetString("ClassName");
        if(string.IsNullOrEmpty(nameSpace))nameSpace = "Entity";
        if(string.IsNullOrEmpty(className))className = table.Name;
    #>
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Data;
     
    namespace <#= nameSpace #>
    {
        /// <summary>
        /// <#= table.Comment == "" ? table.Name : table.Comment.Replace("
    "," ") #>
        /// </summary>
        [Serializable]
        public partial class <#= className+"Entity" #>
        {
    <# foreach (SOColumn c in list)
    {#>
            /// <summary>
            /// <#= c.Comment == "" ? c.Name : c.Comment.Replace("
    "," ") #>
            /// </summary>
            public <#= TypeUtil.DbType2TypeString(c.DataType) #><# if(c.Nullable) {  #><#if(TypeUtil.DbType2Type(c.DataType).IsValueType){ #>?<#
     }#><# }#> <#= c.Name #>{get;set;}; 
                
    <# } #>
        }
    }

    2、生成数据访问层:DAL.tt

    <#@ template language="C#v3.5" hostSpecific="true" debug="true" #><#@ output extension=".cs" #>
    <# 
        TableHost host = (TableHost)(Host); 
        SOTable table = host.Table;
        List<SOColumn> list = host.ColumnList;
    
        string nameSpace = host.GetString("NameSpace");
        string className = host.GetString("ClassName");
        if(string.IsNullOrEmpty(nameSpace))nameSpace = "DAL";
        if(string.IsNullOrEmpty(className))className = table.Name;
        List<SOColumn> listPK = new List<SOColumn>();
        List<SOColumn> listOtherCol =new List<SOColumn>();
    
        List<string> listAdd =new List<string>();
        List<string> listUpdate =new List<string>();
        foreach (SOColumn c in list)
        {           
          if(c.PrimaryKey)
          {
              listPK.Add(c);
          }
          if((c.PrimaryKey&&!c.Identify) ||!c.PrimaryKey )
            {                
             if( !c.Computed)
             {  
                 listOtherCol.Add(c);
                 listAdd.Add("+ "," + SqlNull(entity." + c.Name + ")");
                 if(!c.PrimaryKey) 
                      listUpdate.Add("+ ","+ c.Name + "="+ SqlNull(entity." + c.Name + ")");
            }  
        }}
    
        //colAll     
         System.Text.StringBuilder sbcolAllStr = new StringBuilder();
         List<string> list1= list.ConvertAll(p=>p.Name);
        for (int i = 0; i < list1.Count; i++)
        {
            sbcolAllStr.Append("t."+list[i] + ",");
            if ((i + 1) % 5 == 0 && (i + 1)!=list1.Count ) sbcolAllStr.Append("
                                             ");
        }
        string colAllStr = sbcolAllStr.ToString().TrimEnd(',');
        
        //colOtherStr
        System.Text.StringBuilder sbcolOtherStr = new StringBuilder();
        List<string> list2= listOtherCol.ConvertAll(p=>p.Name);
        for (int i = 0; i < list2.Count; i++)
        {
           if(list2[i].IndexOf("UpdateUser")>-1||list2[i].IndexOf("UpdateTime")>-1)
                continue;
            sbcolOtherStr.Append(list2[i] + ",");
            if ((i + 1) % 5 == 0  && (i + 1)!=list2.Count) sbcolOtherStr.Append("
                                             ");
        }
        string colOtherStr =  sbcolOtherStr.ToString().TrimEnd(',');
         
         
         //AddStr
        System.Text.StringBuilder sblistAddStr = new StringBuilder();
        for (int i = 0; i < listAdd.Count; i++)
        {
               if(listAdd[i].IndexOf("UpdateUser")>-1||listAdd[i].IndexOf("UpdateTime")>-1)
                continue;
            sblistAddStr.Append(listAdd[i] + "");
            if ((i + 1) % 5 == 0  && (i + 1)!=listAdd.Count) sblistAddStr.Append("
                                             ");
        }
        string listAddStr = System.Text.RegularExpressions.Regex.Replace(sblistAddStr.ToString(), @"^+s*"",""s", "");
        
        //UpdateStr
        System.Text.StringBuilder sblistUpdateStr = new StringBuilder();
        for (int i = 0; i < listUpdate.Count; i++)
        {
               if(listUpdate[i].IndexOf("CreateUser")>-1||listUpdate[i].IndexOf("CreateTime")>-1)
                continue;
            sblistUpdateStr.Append(listUpdate[i] + "");
            if ((i + 1) % 5 == 0  && (i + 1)!=listUpdate.Count) sblistUpdateStr.Append("
                                             ");
        }
        string listUpdateStr = System.Text.RegularExpressions.Regex.Replace(sblistUpdateStr.ToString(), @"^+s*"",", "+ "");
    
    #>
    using System;
    using System.Collections.Generic;
    using System.Data;
    using ZS.Mix.Common;
    using <#= className #>.Entity;
    
    namespace <#= nameSpace #>
    {
        internal class <#= className+"DAL" #> : BaseDAL
        {
            /// <summary>
            /// 分页获取所有记录
            /// </summary>
            public List<<#= className #>Entity>  GetAll(<#= TypeUtil.DbType2TypeString(listPK[0].DataType) #> <#= listPK[0].Name #>, int pageindex, int pagesize)
            {
                string sql = string.Format(@"select <#=colAllStr #>                                                                
                                             from   <#= table.Database.Name + "." + table.SchemaName + "." + table.Name #> t
                                             where  t.<#= listPK[0].Name #>  like '%' + '{0}' + '%'
                                             order by  t.<#= listPK[0].Name #> offset ( {1} - 1 ) * {2} rows fetch next {2} rows only;", <#= listPK[0].Name #>, pageindex, pagesize);
                return Service.SqlTable(sql).ToList<<#= className+"Entity" #>>();
             }
             
            /// <summary>
            /// 获取记录总数
            /// </summary>
            public  int GetCount(<#= TypeUtil.DbType2TypeString(listPK[0].DataType) #> <#= listPK[0].Name #>)
            {
                string sql = string.Format(@"select count(1)  
                                             from <#= table.Database.Name + "." + table.SchemaName + "." + table.Name #> t
                                             where  <#= listPK[0].Name #> like '%' + '{0}' + '%';", <#= listPK[0].Name #>);
                return Convert.ToInt32(Service.SqlValueList(sql));
            }
             
            /// <summary>
            /// 获取简要记录
            /// </summary>
            public List<<#= className #>Entity> Get<#= className #>List (<#= TypeUtil.DbType2TypeString(listPK[0].DataType) #> <#= listPK[0].Name #> = "%")
            {
                string sql = string.Format(@"select  <#=colAllStr #>  
                                             from  <#= table.Database.Name + "." + table.SchemaName + "." + table.Name #> t
                                             where t.<#= listPK[0].Name #> like '%' + '{0}' + '%' 
                                             order by t.<#= listPK[0].Name #>", <#= listPK[0].Name #>);
                return Service.SqlTable(sql).ToList<<#= className+"Entity" #>>();
            }
    
            /// <summary>
            /// 获取单个实体
            /// </summary>
            public  <#= className #>Entity Get<#= className #> (<#= TypeUtil.DbType2TypeString(listPK[0].DataType) #> <#= listPK[0].Name #>)
            {
                string sql = string.Format(@" select <#=colAllStr #>  
                                              from <#= table.Database.Name + "." + table.SchemaName + "." + table.Name #> t
                                              where  t.<#= listPK[0].Name #> like '%' + '{0}' + '%';", <#= listPK[0].Name #>);
    
                return Service.SqlTable(sql).ToList<<#= className+"Entity" #>>()[0];
            }
            
            /// <summary>
            /// 是否存在该记录
            /// </summary>
            public bool Exists(<#= TypeUtil.DbType2TypeString(listPK[0].DataType) #> <#= listPK[0].Name #>)
            {
                string sql = string.Format(@"declare @TempID int;SELECT @TempID = count(1)
                                              from <#= table.Database.Name + "." + table.SchemaName + "." + table.Name #> t
                                             where <#= listPK[0].Name #> = '{0}';
                                            if @TempID = 0
                                                select 0;
                                            else
                                                select  1;", <#= listPK[0].Name #>);
    
                int result = Convert.ToInt32(Service.SqlValueList(sql));
                return result == 1 ? true : false;
            }
            /// <summary>
            ///  增加一条数据
            /// </summary>
            public bool Add(<#= className #>Entity entity)
            {
                string sql = @"INSERT INTO <#= table.Database.Name + "." + table.SchemaName + "." + table.Name #>(
                                             <#= colOtherStr #>    
                                            )VALUES("
                                               <#= listAddStr #>  
                                              + " ) ;";
    
                int rowsAffected = Service.SqlExecute(sql);
                return rowsAffected == 1 ? true : false;
            }
    
            /// <summary>
            ///  更新一条数据
            /// </summary>
            public bool Update(<#= className #>Entity entity)
            {
                string sql = @"UPDATE <#= table.Database.Name + "." + table.SchemaName + "." + table.Name #> SET "
                                             <#= listUpdateStr #> 
                              + " WHERE <#=listPK[0].Name #>= '" + <#= "entity."+listPK[0].Name #> +"';";
    
                int rowsAffected = Service.SqlExecute(sql);
                return rowsAffected == 1 ? true : false;
            }
    
            /// <summary>
            /// 删除一条数据
            /// </summary>
            public bool Delete(<#= TypeUtil.DbType2TypeString(listPK[0].DataType) #> <#= listPK[0].Name #>)
            {
                string sql = string.Format(@"DELETE <#= table.Database.Name + "." + table.SchemaName + "." + table.Name #>
                                             WHERE <#= listPK[0].Name #>='{0}';", <#= listPK[0].Name #>);
    
                int rowsAffected = Service.SqlExecute(sql);
                return rowsAffected == 1 ? true : false;
            }
    }
            

    3、注意这个处理null值的函数:

    static public object SqlNull(dynamic obj)
    {
        if (obj == null)
        {
            return "null";
        }
    
        string typename = obj.GetType().Name.Equals("Nullable`1") ? obj.GetType().GetGenericArguments()[0].ToString() : obj.GetType().ToString();
    
        if (typename.Equals("System.String") || typename.Equals("System.Boolean"))
        {
            return "'" + obj.ToString() + "'";
        }
        else if (typename.Equals("System.DateTime"))
        {
            return "convert(datetime,'" + obj.ToString() + "') ";
        }
        else
        {
            return obj.ToString();
        }
    }
  • 相关阅读:
    剑指Offer-30.连续子数组的最大和(C++/Java)
    剑指Offer-29.最小的K个数(C++/Java)
    UVA 1616 Caravan Robbers 商队抢劫者(二分)
    UVA 10570 Meeting with Aliens 外星人聚会
    UVA 11093 Just Finish it up 环形跑道 (贪心)
    UVA 12673 Erratic Expansion 奇怪的气球膨胀 (递推)
    UVA 10954 Add All 全部相加 (Huffman编码)
    UVA 714 Copying Books 抄书 (二分)
    UVALive 3523 Knights of the Round Table 圆桌骑士 (无向图点双连通分量)
    codeforecs Gym 100286B Blind Walk
  • 原文地址:https://www.cnblogs.com/springsnow/p/10365078.html
Copyright © 2020-2023  润新知