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

时间:2022-09-13 10:32:06

一、简介

开源代码生成器-Kalman Studio

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

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

1、软件主要功能如下:

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

二、编写T4模板:

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

首先,打开Visual Studio,新建一个文本文件,将扩展名改为"tt"
T4学习- 4、Kalman Studio-T4代码生成器

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

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

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下的类。

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

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

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

3、自定义SqlServerSchema

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

更改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[]; 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"], -),
Precision = ConvertUtil.ToInt32(row["precision"], -),
Scale = ConvertUtil.ToInt32(row["scale"], –),
}; column.PrimaryKey = pkList.Contains(column.Name);
column.DataType = this.GetDbType(column.NativeType);
column.Comment = GetColumnComment(column);
columnList.Add(column);
} return columnList;
}

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("\r\n"," ") #>
/// </summary>
[Serializable]
public partial class <#= className+"Entity" #>
{
<# foreach (SOColumn c in list)
{#>
/// <summary>
/// <#= c.Comment == "" ? c.Name : c.Comment.Replace("\r\n"," ") #>
/// </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 = ; i < list1.Count; i++)
{
sbcolAllStr.Append("t."+list[i] + ",");
if ((i + ) % == && (i + )!=list1.Count ) sbcolAllStr.Append("\r\n ");
}
string colAllStr = sbcolAllStr.ToString().TrimEnd(','); //colOtherStr
System.Text.StringBuilder sbcolOtherStr = new StringBuilder();
List<string> list2= listOtherCol.ConvertAll(p=>p.Name);
for (int i = ; i < list2.Count; i++)
{
if(list2[i].IndexOf("UpdateUser")>-||list2[i].IndexOf("UpdateTime")>-)
continue;
sbcolOtherStr.Append(list2[i] + ",");
if ((i + ) % == && (i + )!=list2.Count) sbcolOtherStr.Append("\r\n ");
}
string colOtherStr = sbcolOtherStr.ToString().TrimEnd(','); //AddStr
System.Text.StringBuilder sblistAddStr = new StringBuilder();
for (int i = ; i < listAdd.Count; i++)
{
if(listAdd[i].IndexOf("UpdateUser")>-||listAdd[i].IndexOf("UpdateTime")>-)
continue;
sblistAddStr.Append(listAdd[i] + "");
if ((i + ) % == && (i + )!=listAdd.Count) sblistAddStr.Append("\r\n ");
}
string listAddStr = System.Text.RegularExpressions.Regex.Replace(sblistAddStr.ToString(), @"^\+\s*"",""\s", ""); //UpdateStr
System.Text.StringBuilder sblistUpdateStr = new StringBuilder();
for (int i = ; i < listUpdate.Count; i++)
{
if(listUpdate[i].IndexOf("CreateUser")>-||listUpdate[i].IndexOf("CreateTime")>-)
continue;
sblistUpdateStr.Append(listUpdate[i] + "");
if ((i + ) % == && (i + )!=listUpdate.Count) sblistUpdateStr.Append("\r\n ");
}
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[].DataType) #> <#= listPK[].Name #>, int pageindex, int pagesize)
{
string sql = string.Format(@"select <#=colAllStr #>
from <#= table.Database.Name + "." + table.SchemaName + "." + table.Name #> t
where t.<#= listPK[].Name #> like '%' + '{0}' + '%'
order by t.<#= listPK[].Name #> offset ( {} - ) * {} rows fetch next {} rows only;", <#= listPK[0].Name #>, pageindex, pagesize);
return Service.SqlTable(sql).ToList<<#= className+"Entity" #>>();
} /// <summary>
/// 获取记录总数
/// </summary>
public int GetCount(<#= TypeUtil.DbType2TypeString(listPK[].DataType) #> <#= listPK[].Name #>)
{
string sql = string.Format(@"select count(1)
from <#= table.Database.Name + "." + table.SchemaName + "." + table.Name #> t
where <#= listPK[].Name #> like '%' + '{0}' + '%';", <#= listPK[0].Name #>);
return Convert.ToInt32(Service.SqlValueList(sql));
} /// <summary>
/// 获取简要记录
/// </summary>
public List<<#= className #>Entity> Get<#= className #>List (<#= TypeUtil.DbType2TypeString(listPK[].DataType) #> <#= listPK[].Name #> = "%")
{
string sql = string.Format(@"select <#=colAllStr #>
from <#= table.Database.Name + "." + table.SchemaName + "." + table.Name #> t
where t.<#= listPK[].Name #> like '%' + '{0}' + '%'
order by t.<#= listPK[].Name #>", <#= listPK[0].Name #>);
return Service.SqlTable(sql).ToList<<#= className+"Entity" #>>();
} /// <summary>
/// 获取单个实体
/// </summary>
public <#= className #>Entity Get<#= className #> (<#= TypeUtil.DbType2TypeString(listPK[].DataType) #> <#= listPK[].Name #>)
{
string sql = string.Format(@" select <#=colAllStr #>
from <#= table.Database.Name + "." + table.SchemaName + "." + table.Name #> t
where t.<#= listPK[].Name #> like '%' + '{0}' + '%';", <#= listPK[0].Name #>); return Service.SqlTable(sql).ToList<<#= className+"Entity" #>>()[];
} /// <summary>
/// 是否存在该记录
/// </summary>
public bool Exists(<#= TypeUtil.DbType2TypeString(listPK[].DataType) #> <#= listPK[].Name #>)
{
string sql = string.Format(@"declare @TempID int;SELECT @TempID = count(1)
from <#= table.Database.Name + "." + table.SchemaName + "." + table.Name #> t
where <#= listPK[].Name #> = '{0}';
if @TempID =
select ;
else
select ;", <#= listPK[0].Name #>); int result = Convert.ToInt32(Service.SqlValueList(sql));
return result == ? 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 == ? 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[].Name #> +"';"; int rowsAffected = Service.SqlExecute(sql);
return rowsAffected == ? true : false;
} /// <summary>
/// 删除一条数据
/// </summary>
public bool Delete(<#= TypeUtil.DbType2TypeString(listPK[].DataType) #> <#= listPK[].Name #>)
{
string sql = string.Format(@"DELETE <#= table.Database.Name + "." + table.SchemaName + "." + table.Name #>
WHERE <#= listPK[].Name #>='{0}';", <#= listPK[0].Name #>); int rowsAffected = Service.SqlExecute(sql);
return rowsAffected == ? 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()[].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();
}
}

T4学习- 4、Kalman Studio-T4代码生成器的更多相关文章

  1. &lbrack;转&rsqb;发布基于T4模板引擎的代码生成器&lbrack;Kalman Studio&rsqb;

    本文转自:http://www.cnblogs.com/lingyun_k/archive/2010/05/08/1730771.html 自己空闲时间写的一个代码生成器,基于T4模板引擎的,也不仅是 ...

  2. T4学习- 2、创建设计时模板

    使用设计时 T4 文本模板,您可以在 Visual Studio 项目中生成程序代码和其他文件. 通常,您编写一些模板,以便它们根据来自模型的数据来改变所生成的代码. 模型是包含有关应用程序要求的关键 ...

  3. T4学习- 1、简介

    一.T4简介       T4(Text Template Transformation Toolkit)在 Visual Studio 中,"T4 文本模板"是由一些文本块和控制 ...

  4. T4学习- 3、创建运行时模板

    使用 Visual Studio 预处理过的文本模板,可以在运行时在应用程序中生成文本字符串. 执行应用程序的计算机不必具有 Visual Studio. 预处理过的模板有时称为"运行时文本 ...

  5. T4学习资料

    网址:http://www.olegsych.com/2007/12/text-template-transformation-toolkit/

  6. openGL学习:Visual Studio配置OpenGL

    Visual Studio配置OpenGL 分两步: (一)下载glut,并将其放置到适当的位置 (二) 进行vs2005项目属性配置 ******************************** ...

  7. Android学习之Android studio TraceView和lint工具的使用具体解释

    上次讲述了一下Android studio Terminal的使用配置,今天又学习了一下关于Traceview和lint工具的使用. 首先来讲lint吧: Android lint工具是Android ...

  8. 学习OpenCV——Kalman滤波

    背景: 卡尔曼滤波是一种高效率的递归滤波器(自回归滤波器), 它能够从一系列的不完全及包含噪声的测量中,估计动态系统的状态.卡尔曼滤波的一个典型实例是从一组有限的,包含噪声的,对物体位置的观察序列(可 ...

  9. &lbrack;C&plus;&plus;学习历程&rsqb;Visual Studio 2010 的HelloWorld

    大学时期曾学过C++的知识,那时候也没有使用VS这样高档的IDE工具,就是C++6.0那样来的.对于重新拾起C++来说,换了个IDE,那么就先从使用IDE学起吧~ 作者:苏生米沿 本文链接:http: ...

随机推荐

  1. Java-简陋的图书管理

    本文代码为原创一个简陋的管理系统,只做功能的测试.并没有去完善所有应有的功能,只做了输入输出查找.仅供参考! 菜单部分: import java.util.Scanner; public class ...

  2. 最小二乘拟合(转)good

    在物理实验中经常要观测两个有函数关系的物理量.根据两个量的许多组观测数据来确定它们的函数曲线,这就是实验数据处理中的曲线拟合问题.这类问题通常有两种情况:一种是两个观测量x与y之间的函数形式已知,但一 ...

  3. jquery获取form表单内容以及绑定数据到form表单

    在日常开发的过程中,难免会用到form表单,我们需要获取表单的数据保存到数据库,或者拿到后台的一串json数据,要将数据绑定到form表单上,这里我写了一个基于jquery的,formHelp插件,使 ...

  4. 总结:ARM逻辑和高级C(朱老师物联网学习)

    开始学习朱老师物联网的视频是国庆节的那几天开始的,刚刚开始的时候是想自己在网上找一些嵌入式方面的视频资料,也找了很多的资料臂如“国嵌视频”“达内的视频”,之后也化了十几块钱在淘宝上面买了几十个G的视频 ...

  5. yui--datatable 行添加格式

    采用formatter YAHOO.widget.DataTable.Formatter.changeLight=function(elCell, oRecord, oColumn, oData){ ...

  6. Oarcle之事务

    update:更新 例如转账: update emp_ temp set sal = sal-500 where ename = 'JONES':(更新表中sal项 为sal-500 是当ename= ...

  7. Top 10 Revit Architecture 2014 books

    Revit Architecture, along with ArchiCAD, is most used BIM software in architectural design. Although ...

  8. postgresql 脏读-dirtied

    共享缓冲区 在内存中读取或写入数据总是比在任何其他介质上更快.数据库服务器还需要用于快速访问数据的内存,无论是READ还是WRITE访问.在PostgreSQL中,这被称为"共享缓冲区&qu ...

  9. nodejs系列笔记02---模块路径解析

    模块路径解析规则 参考这篇博客 我们已经知道,require函数支持斜杠(/)或盘符(C:)开头的绝对路径,也支持./开头的相对路径.但这两种路径在模块之间建立了强耦合关系,一旦某个模块文件的存放位置 ...

  10. selenium webdriver API详解(三)

    本系列主要讲解webdriver常用的API使用方法(注意:使用前请确认环境是否安装成功,浏览器驱动是否与谷歌浏览器版本对应) 一:获取页面元素的文本内容:text 例:获取我的博客名字文本内容 代码 ...