tt c mysql t4 bll_【框架总结】利用T4模板批量生成代码

很早就看过T4模板的介绍,是可以自定义规则来生成文件的,不过当时没时间研究就跳过了,继续使用动软生成代码。

现在终于抽时间学下T4模板,多亏大神们的无私分享,使我很快就用上T4模板了,灰常灰常感谢大大们~~

在这里我也总结下使用情况,有说的不好的欢迎指出~~

T4文件后缀主要有:tt和ttinclude,tt文件是模板文件,每次保存VS都会提示是否执行代码;ttinclude文件是tt的辅助文件,保存不会提示执行代码。

需要生成代码,一般都是映射数据库了,当然也可以用来生成其他比较统一格式的文件,全看您的模板怎么写,这里我是用来生成映射数据库表的实体类。

(如果想让T4模板代码高亮,有提示,可以下载安装T4模板插件)

6025a287a1c82568711477341f640f9e.png

这是我的T4模板文件结构

1.DBSchema.ttinclude

首先,我是找到一个DBSchema.ttinclude文件,此文件是用来访问数据库,从数据库读出表的信息,代码如下,我根据我自己的情况改动了一些

(由于找资料时没记住出处,忘记是copy哪个大神的了,大神请见谅^_^|||)

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

public classDBSchemaFactory

{public static IDBSchema GetDBSchema(stringdbType)

{

IDBSchema dbSchema;string connectionString =String.Empty;switch(dbType)

{case "SqlServer":

connectionString= "Data Source=.;Initial Catelog=dbName;Persist Security Info=True;User ID=sa;Password=sa;";

dbSchema= newSqlServerSchema(connectionString);break;case "MySql":

connectionString= "Server=localhost;Port=3306;Database=dbName;Uid=root;Pwd=pwd;charset=utf8;";

dbSchema= newMySqlSchema(connectionString);break;default:throw new ArgumentException("The input argument of DatabaseType is invalid!");

}returndbSchema;

}public interfaceIDBSchema

{

List

}public classSqlServerSchema : IDBSchema

{publicSqlConnection conn;public SqlServerSchema(stringconnString)

{

conn= newSqlConnection(connString);

}public List

{

List

conn.Open();var cmd = string.Format(@"SELECT tab.name AS TABLE_NAME, col.name AS COLUMN_NAME,

col.is_identity, per.value AS COLUMN_COMMENT, t.name AS DATA_TYPE

FROM {0}.sys.columns col INNER JOIN {0}.sys.tables tab

ON col.object_id = tab.object_id LEFT JOIN {0}.sys.extended_properties per

ON col.column_id = per.minor_id AND per.major_id = tab.object_id

INNER JOIN {0}.SYS.types t ON col.user_type_id = t.user_type_id", dbName);

SqlCommand command= newSqlCommand(cmd, conn);using(SqlDataReader reader =command.ExecuteReader())

{while(reader.Read())

{string db =dbName,

table= reader["TABLE_NAME"].ToString(),

column= reader["COLUMN_NAME"].ToString(),

type= reader["DATA_TYPE"].ToString(),

comment= reader["COLUMN_COMMENT"].ToString(),

pk= reader["is_identity"].ToString();

Table entity= list.FirstOrDefault(x => x.TableName ==table);if (entity == null)

{

entity= newTable(table);

entity.Columns.Add(newColumn

{

Name=column,

Type=GetCLRType(type),

Comment=comment,

IsPK= pk == "1" ? true : false});

list.Add(entity);

}else{

entity.Columns.Add(newColumn

{

Name=column,

Type=GetCLRType(type),

Comment=comment,

IsPK= pk == "1" ? true : false});

}

}

}

}finally{

conn.Close();

}returnlist;

}

}public classMySqlSchema : IDBSchema

{publicMySqlConnection conn;public MySqlSchema(stringconnString)

{

conn= newMySqlConnection(connString);

}public List

{

List

conn.Open();var cmd = string.Format(@"SELECT `information_schema`.`COLUMNS`.`TABLE_SCHEMA`

,`information_schema`.`COLUMNS`.`TABLE_NAME`

,`information_schema`.`COLUMNS`.`COLUMN_NAME`

,`information_schema`.`COLUMNS`.`DATA_TYPE`

,`information_schema`.`COLUMNS`.`COLUMN_COMMENT`

,`information_schema`.`COLUMNS`.`COLUMN_KEY`

FROM `information_schema`.`COLUMNS`

WHERE `information_schema`.`COLUMNS`.`TABLE_SCHEMA` = '{0}'", dbName);

MySqlCommand command= newMySqlCommand(cmd, conn);using(MySqlDataReader reader =command.ExecuteReader())

{while(reader.Read())

{string db = reader["TABLE_SCHEMA"].ToString(),

table= reader["TABLE_NAME"].ToString(),

column= reader["COLUMN_NAME"].ToString(),

type= reader["DATA_TYPE"].ToString(),

comment= reader["COLUMN_COMMENT"].ToString(),

pk= reader["COLUMN_KEY"].ToString();

Table entity= list.FirstOrDefault(x => x.TableName ==table);if (entity == null)

{

entity= newTable(table);

entity.Columns.Add(newColumn

{

Name=column,

Type=GetCLRType(type),

Comment=comment,

IsPK= pk == "PRI" ? true : false});

list.Add(entity);

}else{

entity.Columns.Add(newColumn

{

Name=column,

Type=GetCLRType(type),

Comment=comment,

IsPK= pk == "PRI" ? true : false});

}

}

}

}finally{

conn.Close();

}returnlist;

}

}public static string GetCLRType(stringdbType)

{switch(dbType)

{case "tinyint":case "smallint":case "mediumint":case "int":case "integer":return "int?";case "double":return "double?";case "float":return "float?";case "decimal":case "numeric":case "real":return "decimal?";case "bit":return "bool?";case "date":case "time":case "year":case "datetime":case "timestamp":return "DateTime?";case "tinyblob":case "blob":case "mediumblob":case "longblog":case "binary":case "varbinary":return "byte[]";case "char":case "varchar":case "tinytext":case "text":case "mediumtext":case "longtext":return "string";case "point":case "linestring":case "polygon":case "geometry":case "multipoint":case "multilinestring":case "multipolygon":case "geometrycollection":case "enum":case "set":default:returndbType;

}

}

}public classTable

{publicTable()

{this.Columns = new List();

}public Table(stringname)

:this()

{this.TableName =name;

}public string TableName { get; set; }public List Columns { get; set; }

}public classColumn

{//字段名

public string Name { get; set; }//类型

public string Type { get; set; }//备注

public string Comment { get; set; }//是否主键

public bool IsPK { get; set; }

}

#>

DBSchema.ttinclude

原先copy的只有针对SQL Server的,不过我需要MySql,所以上网找了个连接MySql的加上了。

--

这里的$(ProjectDir)当前项目所在目录路径,还可以用其他:

$(SolutionDir):当前项目所在解决方案目录

$(ProjectDir):当前项目所在目录

$(TargetPath):当前项目编译输出文件绝对路径

$(TargetDir):当前项目编译输出目录

-- public bool IsPK { get; set; }  //这个是我用来记录该列是否主键,我生成实体类时需要用到,不需要可以去掉

SQL Server是通过sys.columns.is_identity获取,MySql是通过information_schema.COLUMNS.COLUMN_KEY获取。

OK,其他没怎么改动过了。

2.MultDocument.ttinclude

数据库连接有了,不过我根据大神的分享,生成实体类,发现每次只能生成一个表实体类,这完全不合理嘛,于是又上网找了下批量生成的资料。。。

很快就找到MultDocument.ttinclude文件了,据介绍,是外国一个大神分享的,这个文件没什么改的,我就直接用了一 一+

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

//T4 Template Block manager for handling multiple file outputs more easily.//Copyright (c) Microsoft Corporation. All rights reserved.//This source code is made available under the terms of the Microsoft Public License (MS-PL)//Manager class records the various blocks so it can split them u

classManager

{public structBlock

{publicString Name;public intStart, Length;

}public List blocks = new List();publicBlock currentBlock;public Block footerBlock = newBlock();public Block headerBlock = newBlock();publicITextTemplatingEngineHost host;publicManagementStrategy strategy;publicStringBuilder template;public String OutputPath { get; set; }public Manager(ITextTemplatingEngineHost host, StringBuilder template, boolcommonHeader)

{this.host =host;this.template =template;

OutputPath=String.Empty;

strategy=ManagementStrategy.Create(host);

}public voidStartBlock(String name)

{

currentBlock= new Block { Name = name, Start =template.Length };

}public voidStartFooter()

{

footerBlock.Start=template.Length;

}public voidEndFooter()

{

footerBlock.Length= template.Length -footerBlock.Start;

}public voidStartHeader()

{

headerBlock.Start=template.Length;

}public voidEndHeader()

{

headerBlock.Length= template.Length -headerBlock.Start;

}public voidEndBlock()

{

currentBlock.Length= template.Length -currentBlock.Start;

blocks.Add(currentBlock);

}public void Process(boolsplit)

{

String header=template.ToString(headerBlock.Start, headerBlock.Length);

String footer=template.ToString(footerBlock.Start, footerBlock.Length);

blocks.Reverse();foreach (Block block inblocks)

{

String fileName=Path.Combine(OutputPath, block.Name);if(split)

{

String content= header + template.ToString(block.Start, block.Length) +footer;

strategy.CreateFile(fileName, content);

template.Remove(block.Start, block.Length);

}else{

strategy.DeleteFile(fileName);

}

}

}

}classManagementStrategy

{internal staticManagementStrategy Create(ITextTemplatingEngineHost host)

{return (host is IServiceProvider) ? new VSManagementStrategy(host) : newManagementStrategy(host);

}internalManagementStrategy(ITextTemplatingEngineHost host) { }internal virtual voidCreateFile(String fileName, String content)

{

File.WriteAllText(fileName, content);

}internal virtual void DeleteFile(stringfileName)

{if(File.Exists(fileName))

File.Delete(fileName);

}

}classVSManagementStrategy: ManagementStrategy

{privateEnvDTE.ProjectItem templateProjectItem;internalVSManagementStrategy(ITextTemplatingEngineHost host)

:base(host)

{

IServiceProvider hostServiceProvider=(IServiceProvider)host;if (hostServiceProvider == null)throw new ArgumentNullException("Could not obtain hostServiceProvider");

EnvDTE.DTE dte= (EnvDTE.DTE)hostServiceProvider.GetService(typeof(EnvDTE.DTE));if (dte == null)throw new ArgumentNullException("Could not obtain DTE from host");

templateProjectItem=dte.Solution.FindProjectItem(host.TemplateFile);

}internal override voidCreateFile(String fileName, String content)

{base.CreateFile(fileName, content);

((EventHandler)delegate{

templateProjectItem.ProjectItems.AddFromFile(fileName);

}).BeginInvoke(null, null, null, null);

}internal override voidDeleteFile(String fileName)

{

((EventHandler)delegate{

FindAndDeleteFile(fileName);

}).BeginInvoke(null, null, null, null);

}private voidFindAndDeleteFile(String fileName)

{foreach (EnvDTE.ProjectItem projectItem intemplateProjectItem.ProjectItems)

{if (projectItem.get_FileNames(0) ==fileName)

{

projectItem.Delete();return;

}

}

}

}

#>

MultDocument.ttinclude

各位看官,直接copy存为ttinclude就可以了。

3.CommonAttr.ttinclude

准备工作差不多了,不过在写tt模板之前,我先说下我抽出来的公用参数/方法。

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

public classAttributes

{//文件版权信息

public static string Copyright = DateTime.Now.Year + "RoryLiu All Rights Reserved";public static Version Version =Environment.Version;public static string Author = "auto generated by T4";public static string DbType = "MySql";//数据库类型

public static string DbName = "dbName";//数据库名

public static string ProName = "Namespace";//命名空间

public static bool IsGo = true;//是否执行

public static string TableNames = "*";//全部用"*",部分表用",表名,表名,..."

}//得到属性的Pascial风格名称,比如my_table => MyTable

public string GetPropertyPascialName(stringsource)

{string[] s = source.Split('_');for(int i = 0; i < s.Length; i++)

{string s1 = s[i].Substring(0, 1).ToUpper();string s2 = s[i].Substring(1);

s[i]=String.Concat(s1,s2);

}returnString.Concat(s);

}

#>

CommonAttr.ttinclude

将这些参数抽出来主要是为了方便生成Model、DAL、BLL等模板,不一定要用这个文件。

4.ModelTemp.tt

准备工作都做完了,终于到模板了,各位看官等急了吧,先给大家看下生成实体类的模板:(ModelTemp.tt其实也是上网找的,然后自己再修改( ‵▽′)ψ)

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

if (!Attributes.IsGo) return "";//命名空间

var nsName = Attributes.ProName + ".Models";//实例化生成模板

var manager = new Manager(Host, GenerationEnvironment, true) { OutputPath =Path.GetDirectoryName(Host.TemplateFile)};//获取连接的数据库

var dbSchema =DBSchemaFactory.GetDBSchema(Attributes.DbType);//获取数据库下的所有表

var entities =dbSchema.GetTables(Attributes.DbName);//实体名

var entityName = "";foreach(Table entity inentities)

{//只生成指定的表实体

if (!Attributes.TableNames.Equals("*") && !Attributes.TableNames.Contains("," + entity.TableName + ","))continue;//生成实体名

entityName =GetPropertyPascialName(entity.TableName);

manager.StartBlock(entityName+ ".cs");

Column pkCol= entity.Columns.Find(c =>c.IsPK);foreach (var col inentity.Columns)

{if(col.IsPK)

{

pkCol=col;break;

}

}

#>

//-----------------------------------------------------------------------* Copyright (C) //* version : //* author : //* FileName: .cs//* history : Created by T4 -----------------------------------------------------------------------

usingSystem;usingSystem.ComponentModel.DataAnnotations;namespace {///

/// Entity Model///

[Serializable]

[Table("")]public partial class {public () { }

{

#>

///

///

///

{

#>[Key]

}

#>

public { get; set; }

}

#>}

}

manager.EndBlock();

}

manager.Process(true);

#>

ModelTemp.tt

头部有三个,相信大家都知道是神马了,没错,就是引用前面准备的三个ttinclude文件。

-- Attributes.IsGo,其实这个不用也没什么影响,我是因为不想每次保存都弹出提示是否执行才加的,我设置成不再提示,然后用IsGo来判断是否执行

-- 实体名我没用数据库表名,而是通过GetPropertyPascialName()将表名变成Pascial风格,真正的表名我是写在自定义特性Table里

-- 循环所有表时,我是通过Attributes.TableNames来确定哪些表要生成文件,这样后期有改动某个表时不需要全部生成

-- 为了给主键属性加上特性[Key],我是通过IsPK来判断

模板基本就改了这些。

5.Table.cs

Table类是自定义特性,继承了System.Attribute,代码如下:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

///

///映射数据库表对象///

[AttributeUsageAttribute(AttributeTargets.Class, Inherited = false, AllowMultiple = false), Serializable]public classTable : Attribute

{///

///表名称///

public stringTableName;public Table(stringtblName)

{

TableName=tblName;

}

}

Table.cs

我是直接放在根目录下,当然如果有多个自定义特性时,还是建议建个文件夹。

好了,现在只要把CommonAttr里的IsGo改为true,DBSchema里的connectionString改成您本地的mysql就可以保存ModelTemp来生成了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值