分享

构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(29)

 ThinkTank_引擎 2014-03-23
  • 这讲适合所有的MVC程序

    很荣幸,我们的系统有了体验的地址了。演示地址

    之前我们发布了一个简单的代码生成器,其原理就是读取数据库的表结构,生成文本的一个方式来生成代码!

    为了替代重复的劳动,微软自己有一套T4模版,我不想把T4模版说得那么的复杂,因为这个复杂我自己也不知道。

    原理跟市面的代码生成器一个道理,但是T4的扩展比代码生成器更灵活,可以更方便根据类生成代码等操作。

    T4代码模式是没有颜色高亮了,但是我们的VS支持插件 T4 Editor

    下载安装之后就可以跟我们写C#一样有智能高亮和提示了。

    新建一个项目,专门用于T4的存放。

    \

    首先我们要让T4连接我们的数据库

    新建一个DbHelper.ttinclude模版包含文件

    加载中...加载中...
    001.<#+
    002.public class DbHelper
    003.{
    004.#region GetDbTables
    005. 
    006.public static List<DbTable> GetDbTables(string connectionString, string database, string tables = null)
    007.{
    008. 
    009.if (!string.IsNullOrEmpty(tables))
    010.{
    011.tables = string.Format(" and obj.name in ('{0}')", tables.Replace(",", "','"));
    012.}
    013.#region SQL
    014.string sql = string.Format(@"SELECT
    015.obj.name tablename,
    016.schem.name schemname,
    017.idx.rows,
    018.CAST
    019.(
    020.CASE
    021.WHEN (SELECT COUNT(1) FROM sys.indexes WHERE object_id= obj.OBJECT_ID AND is_primary_key=1) >=1 THEN 1
    022.ELSE 0
    023.END
    024.AS BIT) HasPrimaryKey                                        
    025.from {0}.sys.objects obj
    026.inner join {0}.dbo.sysindexes idx on obj.object_id=idx.id and idx.indid<=1
    027.INNER JOIN {0}.sys.schemas schem ON obj.schema_id=schem.schema_id
    028.where type='U' {1}
    029.order by obj.name", database, tables);
    030.#endregion
    031.DataTable dt = GetDataTable(connectionString, sql);
    032.return dt.Rows.Cast<DataRow>().Select(row => new DbTable
    033.{
    034.TableName = row.Field<string>("tablename"),
    035.SchemaName = row.Field<string>("schemname"),
    036.Rows = row.Field<int>("rows"),
    037.HasPrimaryKey = row.Field<bool>("HasPrimaryKey")
    038.}).ToList();
    039.}
    040.#endregion
    041. 
    042.#region GetDbColumns
    043. 
    044.public static List<DbColumn> GetDbColumns(string connectionString, string database, string tableName, string schema = "dbo")
    045.{
    046.#region SQL
    047.string sql = string.Format(@"
    048.WITH indexCTE AS
    049.(
    050.SELECT
    051.ic.column_id,
    052.ic.index_column_id,
    053.ic.object_id   
    054.FROM {0}.sys.indexes idx
    055.INNER JOIN {0}.sys.index_columns ic ON idx.index_id = ic.index_id AND idx.object_id = ic.object_id
    056.WHERE  idx.object_id =OBJECT_ID(@tableName) AND idx.is_primary_key=1
    057.)
    058.select
    059.colm.column_id ColumnID,
    060.CAST(CASE WHEN indexCTE.column_id IS NULL THEN 0 ELSE 1 END AS BIT) IsPrimaryKey,
    061.colm.name ColumnName,
    062.systype.name ColumnType,
    063.colm.is_identity IsIdentity,
    064.colm.is_nullable IsNullable,
    065.cast(colm.max_length as int) ByteLength,
    066.(
    067.case
    068.when systype.name='nvarchar' and colm.max_length>0 then colm.max_length/2
    069.when systype.name='nchar' and colm.max_length>0 then colm.max_length/2
    070.when systype.name='ntext' and colm.max_length>0 then colm.max_length/2
    071.else colm.max_length
    072.end
    073.) CharLength,
    074.cast(colm.precision as int) Precision,
    075.cast(colm.scale as int) Scale,
    076.prop.value Remark
    077.from {0}.sys.columns colm
    078.inner join {0}.sys.types systype on colm.system_type_id=systype.system_type_id and colm.user_type_id=systype.user_type_id
    079.left join {0}.sys.extended_properties prop on colm.object_id=prop.major_id and colm.column_id=prop.minor_id
    080.LEFT JOIN indexCTE ON colm.column_id=indexCTE.column_id AND colm.object_id=indexCTE.object_id                                       
    081.where colm.object_id=OBJECT_ID(@tableName)
    082.order by colm.column_id", database);
    083.#endregion
    084.SqlParameter param = new SqlParameter("@tableName", SqlDbType.NVarChar, 100) { Value = string.Format("{0}.{1}.{2}", database, schema, tableName) };
    085.DataTable dt = GetDataTable(connectionString, sql, param);
    086.return dt.Rows.Cast<DataRow>().Select(row => new DbColumn()
    087.{
    088.ColumnID = row.Field<int>("ColumnID"),
    089.IsPrimaryKey = row.Field<bool>("IsPrimaryKey"),
    090.ColumnName = row.Field<string>("ColumnName"),
    091.ColumnType = row.Field<string>("ColumnType"),
    092.IsIdentity = row.Field<bool>("IsIdentity"),
    093.IsNullable = row.Field<bool>("IsNullable"),
    094.ByteLength = row.Field<int>("ByteLength"),
    095.CharLength = row.Field<int>("CharLength"),
    096.Scale = row.Field<int>("Scale"),
    097.Remark = row["Remark"].ToString()
    098.}).ToList();
    099.}
    100. 
    101.#endregion    
    102. 
    103. 
    104.#region GetDataTable
    105. 
    106.public static DataTable GetDataTable(string connectionString, string commandText, params SqlParameter[] parms)
    107.{
    108.using (SqlConnection connection = new SqlConnection(connectionString))
    109.{
    110.SqlCommand command = connection.CreateCommand();
    111.command.CommandText = commandText;
    112.command.Parameters.AddRange(parms);
    113.SqlDataAdapter adapter = new SqlDataAdapter(command);
    114. 
    115.DataTable dt = new DataTable();
    116.adapter.Fill(dt);
    117. 
    118.return dt;
    119.}
    120.}
    121. 
    122.#endregion
    123.}
    124. 
    125.#region DbTable
    126./// <summary>
    127./// 表结构
    128./// </summary>
    129.public sealed class DbTable
    130.{
    131./// <summary>
    132./// 表名称
    133./// </summary>
    134.public string TableName { get; set; }
    135./// <summary>
    136./// 表的架构
    137./// </summary>
    138.public string SchemaName { get; set; }
    139./// <summary>
    140./// 表的记录数
    141./// </summary>
    142.public int Rows { get; set; }
    143. 
    144./// <summary>
    145./// 是否含有主键
    146./// </summary>
    147.public bool HasPrimaryKey { get; set; }
    148.}
    149.#endregion
    150. 
    151.#region DbColumn
    152./// <summary>
    153./// 表字段结构
    154./// </summary>
    155.public sealed class DbColumn
    156.{
    157./// <summary>
    158./// 字段ID
    159./// </summary>
    160.public int ColumnID { get; set; }
    161. 
    162./// <summary>
    163./// 是否主键
    164./// </summary>
    165.public bool IsPrimaryKey { get; set; }
    166. 
    167./// <summary>
    168./// 字段名称
    169./// </summary>
    170.public string ColumnName { get; set; }
    171. 
    172./// <summary>
    173./// 字段类型
    174./// </summary>
    175.public string ColumnType { get; set; }
    176. 
    177./// <summary>
    178./// 数据库类型对应的C#类型
    179./// </summary>
    180.public string CSharpType
    181.{
    182.get
    183.{
    184.return SqlServerDbTypeMap.MapCsharpType(ColumnType);
    185.}
    186.}
    187. 
    188./// <summary>
    189.///
    190./// </summary>
    191.public Type CommonType
    192.{
    193.get
    194.{
    195.return SqlServerDbTypeMap.MapCommonType(ColumnType);
    196.}
    197.}
    198. 
    199./// <summary>
    200./// 字节长度
    201./// </summary>
    202.public int ByteLength { get; set; }
    203. 
    204./// <summary>
    205./// 字符长度
    206./// </summary>
    207.public int CharLength { get; set; }
    208. 
    209./// <summary>
    210./// 小数位
    211./// </summary>
    212.public int Scale { get; set; }
    213. 
    214./// <summary>
    215./// 是否自增列
    216./// </summary>
    217.public bool IsIdentity { get; set; }
    218. 
    219./// <summary>
    220./// 是否允许空
    221./// </summary>
    222.public bool IsNullable { get; set; }
    223. 
    224./// <summary>
    225./// 描述
    226./// </summary>
    227.public string Remark { get; set; }
    228.}
    229.#endregion
    230. 
    231.#region SqlServerDbTypeMap
    232. 
    233.public class SqlServerDbTypeMap
    234.{
    235.public static string MapCsharpType(string dbtype)
    236.{
    237.if (string.IsNullOrEmpty(dbtype)) return dbtype;
    238.dbtype = dbtype.ToLower();
    239.string csharpType = "object";
    240.switch (dbtype)
    241.{
    242.case "bigint": csharpType = "long"; break;
    243.case "binary": csharpType = "byte[]"; break;
    244.case "bit": csharpType = "bool"; break;
    245.case "char": csharpType = "string"; break;
    246.case "date": csharpType = "DateTime"; break;
    247.case "datetime": csharpType = "DateTime"; break;
    248.case "datetime2": csharpType = "DateTime"; break;
    249.case "datetimeoffset": csharpType = "DateTimeOffset"; break;
    250.case "decimal": csharpType = "decimal"; break;
    251.case "float": csharpType = "double"; break;
    252.case "image": csharpType = "byte[]"; break;
    253.case "int": csharpType = "int"; break;
    254.case "money": csharpType = "decimal"; break;
    255.case "nchar": csharpType = "string"; break;
    256.case "ntext": csharpType = "string"; break;
    257.case "numeric": csharpType = "decimal"; break;
    258.case "nvarchar": csharpType = "string"; break;
    259.case "real": csharpType = "Single"; break;
    260.case "smalldatetime": csharpType = "DateTime"; break;
    261.case "smallint": csharpType = "short"; break;
    262.case "smallmoney": csharpType = "decimal"; break;
    263.case "sql_variant": csharpType = "object"; break;
    264.case "sysname": csharpType = "object"; break;
    265.case "text": csharpType = "string"; break;
    266.case "time": csharpType = "TimeSpan"; break;
    267.case "timestamp": csharpType = "byte[]"; break;
    268.case "tinyint": csharpType = "byte"; break;
    269.case "uniqueidentifier": csharpType = "Guid"; break;
    270.case "varbinary": csharpType = "byte[]"; break;
    271.case "varchar": csharpType = "string"; break;
    272.case "xml": csharpType = "string"; break;
    273.default: csharpType = "object"; break;
    274.}
    275.return csharpType;
    276.}
    277. 
    278.public static Type MapCommonType(string dbtype)
    279.{
    280.if (string.IsNullOrEmpty(dbtype)) return Type.Missing.GetType();
    281.dbtype = dbtype.ToLower();
    282.Type commonType = typeof(object);
    283.switch (dbtype)
    284.{
    285.case "bigint": commonType = typeof(long); break;
    286.case "binary": commonType = typeof(byte[]); break;
    287.case "bit": commonType = typeof(bool); break;
    288.case "char": commonType = typeof(string); break;
    289.case "date": commonType = typeof(DateTime); break;
    290.case "datetime": commonType = typeof(DateTime); break;
    291.case "datetime2": commonType = typeof(DateTime); break;
    292.case "datetimeoffset": commonType = typeof(DateTimeOffset); break;
    293.case "decimal": commonType = typeof(decimal); break;
    294.case "float": commonType = typeof(double); break;
    295.case "image": commonType = typeof(byte[]); break;
    296.case "int": commonType = typeof(int); break;
    297.case "money": commonType = typeof(decimal); break;
    298.case "nchar": commonType = typeof(string); break;
    299.case "ntext": commonType = typeof(string); break;
    300.case "numeric": commonType = typeof(decimal); break;
    301.case "nvarchar": commonType = typeof(string); break;
    302.case "real": commonType = typeof(Single); break;
    303.case "smalldatetime": commonType = typeof(DateTime); break;
    304.case "smallint": commonType = typeof(short); break;
    305.case "smallmoney": commonType = typeof(decimal); break;
    306.case "sql_variant": commonType = typeof(object); break;
    307.case "sysname": commonType = typeof(object); break;
    308.case "text": commonType = typeof(string); break;
    309.case "time": commonType = typeof(TimeSpan); break;
    310.case "timestamp": commonType = typeof(byte[]); break;
    311.case "tinyint": commonType = typeof(byte); break;
    312.case "uniqueidentifier": commonType = typeof(Guid); break;
    313.case "varbinary": commonType = typeof(byte[]); break;
    314.case "varchar": commonType = typeof(string); break;
    315.case "xml": commonType = typeof(string); break;
    316.default: commonType = typeof(object); break;
    317.}
    318.return commonType;
    319.}
    320.}
    321.#endregion
    322. 
    323. 
    324.#>
    DbHelper.ttinclude

    这里面包含了一些转换的方法和访问数据库的SQL语句

    其中GetDbTables方法就是根据数据库的链接,表名来读取字段数据

    怎么用呢?就是让模版包含这个文件,就可以访问方法了

    举一个Model为例吧,新建Model文件夹。并新建文件,模版文件为tt结尾的扩展

    \

    我们新建Test.tt之后

    1.<#@ template debug="false" hostspecific="false" language="C#" #>
    2.<#@ assembly name="System.Core" #>
    3.<#@ import namespace="System.Linq" #>
    4.<#@ import namespace="System.Text" #>
    5.<#@ import namespace="System.Collections.Generic" #>
    6.<#@ output extension=".txt" #>

    最后一行<#@ output extension=".txt" #>

    为模版生成的文件,可以是.cs可以是其他。我们就不改了,就是txt

    如果是cs类,生成会编译,如果代码是对的,但是系统不知道是对的,会编译出错,虽然这不影响结果,但是不爽

    我们为Test.tt添加如下代码

    01.<#@ template debug="false" hostspecific="false" language="C#" #>
    02.<#@ output extension=".txt" #>
    03.<#@ assembly name="System.Core.dll" #>
    04.<#@ assembly name="System.Data.dll" #>
    05.<#@ assembly name="System.Data.DataSetExtensions.dll" #>
    06.<#@ assembly name="System.Xml.dll" #>
    07.<#@ import namespace="System" #>
    08.<#@ import namespace="System.Xml" #>
    09.<#@ import namespace="System.Linq" #>
    10.<#@ import namespace="System.Data" #>
    11.<#@ import namespace="System.Data.SqlClient" #>
    12.<#@ import namespace="System.Collections.Generic" #>
    13.<#@ import namespace="System.IO" #>
    14.<#@ include file="$(ProjectDir)DbHelper.ttinclude"  #>
    15.//------------------------------------------------------------------------------
    16.// <auto-generated>
    17.//     此代码由T4模板自动生成
    18.//       生成时间 <#=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")#> by YmNets
    19.//     对此文件的更改可能会导致不正确的行为,并且如果
    20.//     重新生成代码,这些更改将会丢失。
    21.// </auto-generated>
    22.//------------------------------------------------------------------------------

    我们引入了一些命名空间,因为我们要将读到的表结构进行一系列的处理,比如for循环等操作

    其中<#@ include file="$(ProjectDir)DbHelper.ttinclude"  #>就是包含了刚刚简历的访问数据库文件

    T4模版的语法通过上面我们可以看出是<#@#>,<#=#>,<##>,<#+#>结构跟原生的asp.net一个鸟样,不是Razor语法,这里要注意

    我们添加一些代码

    01.<#@ template debug="false" hostspecific="false" language="C#" #>
    02.<#@ output extension=".txt" #>
    03.<#@ assembly name="System.Core.dll" #>
    04.<#@ assembly name="System.Data.dll" #>
    05.<#@ assembly name="System.Data.DataSetExtensions.dll" #>
    06.<#@ assembly name="System.Xml.dll" #>
    07.<#@ import namespace="System" #>
    08.<#@ import namespace="System.Xml" #>
    09.<#@ import namespace="System.Linq" #>
    10.<#@ import namespace="System.Data" #>
    11.<#@ import namespace="System.Data.SqlClient" #>
    12.<#@ import namespace="System.Collections.Generic" #>
    13.<#@ import namespace="System.IO" #>
    14.<#@ include file="$(ProjectDir)DbHelper.ttinclude"  #>
    15.//------------------------------------------------------------------------------
    16.// <auto-generated>
    17.//     此代码由T4模板自动生成
    18.//       生成时间 <#=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")#> by YmNets
    19.//     对此文件的更改可能会导致不正确的行为,并且如果
    20.//     重新生成代码,这些更改将会丢失。
    21.// </auto-generated>
    22.//------------------------------------------------------------------------------
    23.using System;
    24.using System.ComponentModel.DataAnnotations;
    25.namespace <#=config.nameSpace#>
    26.{   
    27. 
    28.public class <#=config.TableName#>Model
    29.{
    30.<# foreach(DbColumn column in DbHelper.GetDbColumns(config.ConnectionString, config.DbDatabase, config.TableName)){#>
    31.public <#= column.CSharpType#><# if(column.CommonType.IsValueType && column.IsNullable){#>?<#}#> <#=column.ColumnName#> { get; set; }
    32.<#}#>
    33.}
    34.}
    35.<#+
    36.public class config
    37.{
    38.public static readonly string ConnectionString="Data Source=(local);Initial Catalog=AppDB;User ID=sa;Pass<a href="http://www.it165.net/edu/ebg/" target="_blank" class="keylink">word</a>=zhaoyun123!@#;";
    39.public static readonly string DbDatabase="AppDB";
    40.public static readonly string TableName="SysSample";
    41.public static readonly string nameSpace="App.Sys";
    42.}
    43.#>

    有一些通用的我建了一个类config,访问config只需要config.TableName即可

    访问DbHelper.ttinclude,值需要DbHelper.***即可

    所以同道理,通用的类我们可以建造 Common.ttinclude来完善模版生成库

    OK。配置好之后,值需要展开Test.tt就可以看到Test.txt文件,文件生成情况如下

    01.//------------------------------------------------------------------------------
    02.// <auto-generated>
    03.//     此代码由T4模板自动生成
    04.//       生成时间 2014-03-03 17:34:45 by YmNets
    05.//     对此文件的更改可能会导致不正确的行为,并且如果
    06.//     重新生成代码,这些更改将会丢失。
    07.// </auto-generated>
    08.//------------------------------------------------------------------------------
    09.using System;
    10.using System.ComponentModel.DataAnnotations;
    11.namespace App.Sys
    12.{   
    13. 
    14.public class SysSampleModel
    15.{
    16.public string Id { get; set; }
    17.public string Name { get; set; }
    18.public int? Age { get; set; }
    19.public DateTime? Bir { get; set; }
    20.public string Photo { get; set; }
    21.public string Note { get; set; }
    22.public DateTime? CreateTime { get; set; }
    23. 
    24.}
    25.}

    非常快速,所以,你可以很快建立自己项目的模版文件了。

    以上只是基础,我们更加关心的是更多的扩展,比如判断数据库类型啊等等,做逻辑处理,获取字段的长度做处理啊。

    所以我给大家提供一个备注:下面这条语句可以得到表的结构

    1.<# foreach(DbColumn column in DbHelper.GetDbColumns(config.ConnectionString, config.DbDatabase, config.TableName)){#>
    2.<#}#>

    其中:

    column.CSharpType              字段的类型

    column.IsNullable                  是否为空

    column.IsPrimaryKey             是否是主键

    column.CharLength               字段的长度,如varchar(50)那么column.CharLength=50

    column.ColumnName             字段的名称

    样例:判断是否DataTime类型

    1.<#if(column.CSharpType=="DateTime"){#>
    2. 
    3.<# } #>

    一个小小的例子,我们就能看懂MVC的T4模版,并能熟练运用它


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多