你的位置:首页 > ASP.net教程

[ASP.net教程]NFine框架的T4模板


1.前言

前段时间在网上看到一个开源框架很好的。开源:ASP.NET MVC+EF6+Bootstrap开发框架,写代码就是比较比较麻烦,分层比较多,对于我这种偷懒的人就想到了写一个T4模板。不了解框架的可以先去看一下这个开源的框架。

一起有5个层,也就是意味着每次数据库添加一张表,就需要写这5个类。

2.NFine.Domain.Entity

<#@ template debug="false" hostspecific="false" language="C#" #><#@ output extension=".cs" #><#@ assembly name="System.Core.dll" #><#@ assembly name="System.Data.dll" #><#@ assembly name="System.Data.DataSetExtensions.dll" #><#@ assembly name="System." #><#@ import namespace="System" #><#@ import namespace="System." #><#@ import namespace="System.Linq" #><#@ import namespace="System.Data" #><#@ import namespace="System.Data.SqlClient" #><#@ import namespace="System.Collections.Generic" #><#@ import namespace="System.IO" #><#@ include file="$(ProjectDir)DbHelper.ttinclude" #>//------------------------------------------------------------------------------// <博客园-枫伶忆 http://www.cnblogs.com/fenglingyi/>//   此代码由T4模板自动生成//    生成时间 <#=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")#> by 枫伶忆//   对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。//   QQ:549387177// <博客园-枫伶忆 http://www.cnblogs.com/fenglingyi/>//------------------------------------------------------------------------------<#   var tableName=config.TableName.Replace("Sys_","")+"Entity";   #>using System;namespace NFine.Domain.Entity.SystemManage{    /// <summary>  /// <#=tableName#>  /// </summary>    public class <#=tableName#>:IEntity<<#=tableName#>>, ICreationAudited, IDeleteAudited, IModificationAudited  {<# foreach(DbColumn column in DbHelper.GetDbColumns(config.ConnectionString, config.DbDatabase, config.TableName)){#>   public <#= column.CSharpType#><# if(column.CommonType.IsValueType && column.IsNullable){#>?<#}#> <#=column.ColumnName#> { get; set; }<#}#>   }}

3.NFine.Domain.IRepository

<#@ template debug="false" hostspecific="false" language="C#" #><#@ output extension=".cs" #><#@ assembly name="System.Core.dll" #><#@ assembly name="System.Data.dll" #><#@ assembly name="System.Data.DataSetExtensions.dll" #><#@ assembly name="System." #><#@ import namespace="System" #><#@ import namespace="System." #><#@ import namespace="System.Linq" #><#@ import namespace="System.Data" #><#@ import namespace="System.Data.SqlClient" #><#@ import namespace="System.Collections.Generic" #><#@ import namespace="System.IO" #><#@ include file="$(ProjectDir)DbHelper.ttinclude" #>//------------------------------------------------------------------------------// <博客园-枫伶忆 http://www.cnblogs.com/fenglingyi/>//   此代码由T4模板自动生成//    生成时间 <#=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")#> by 枫伶忆//   对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。//   QQ:549387177// <博客园-枫伶忆 http://www.cnblogs.com/fenglingyi/>//------------------------------------------------------------------------------<#   var tableName=config.TableName.Replace("Sys_","")+"Repository";  var entity=config.TableName.Replace("Sys_","")+"Entity"; #>using NFine.Data;using NFine.Domain.Entity.SystemManage;using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace NFine.Domain.IRepository.SystemManage{    /// <summary>  /// <#=tableName#>  /// </summary>    public interface I<#=tableName#>:IRepositoryBase<<#=entity#>>  {  }}

 

4.NFine.Repository

<#@ template debug="false" hostspecific="false" language="C#" #><#@ output extension=".cs" #><#@ assembly name="System.Core.dll" #><#@ assembly name="System.Data.dll" #><#@ assembly name="System.Data.DataSetExtensions.dll" #><#@ assembly name="System." #><#@ import namespace="System" #><#@ import namespace="System." #><#@ import namespace="System.Linq" #><#@ import namespace="System.Data" #><#@ import namespace="System.Data.SqlClient" #><#@ import namespace="System.Collections.Generic" #><#@ import namespace="System.IO" #><#@ include file="$(ProjectDir)DbHelper.ttinclude" #>//------------------------------------------------------------------------------// <博客园-枫伶忆 http://www.cnblogs.com/fenglingyi/>//   此代码由T4模板自动生成//    生成时间 <#=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")#> by 枫伶忆//   对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。//   QQ:549387177// <博客园-枫伶忆 http://www.cnblogs.com/fenglingyi/>//------------------------------------------------------------------------------<#   var tableName=config.TableName.Replace("Sys_","")+"Repository";  var entity=config.TableName.Replace("Sys_","")+"Entity"; #>using NFine.Data;using NFine.Domain.Entity.SystemManage;using NFine.Domain.IRepository.SystemManage;using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace NFine.Repository.SystemManage{    /// <summary>  /// <#=tableName#>  /// </summary>    public class <#=tableName#>:RepositoryBase<<#=entity#>>,I<#=tableName#>  {  }}

 

5.NFine.Mapping

<#@ template debug="false" hostspecific="false" language="C#" #><#@ output extension=".cs" #><#@ assembly name="System.Core.dll" #><#@ assembly name="System.Data.dll" #><#@ assembly name="System.Data.DataSetExtensions.dll" #><#@ assembly name="System." #><#@ import namespace="System" #><#@ import namespace="System." #><#@ import namespace="System.Linq" #><#@ import namespace="System.Data" #><#@ import namespace="System.Data.SqlClient" #><#@ import namespace="System.Collections.Generic" #><#@ import namespace="System.IO" #><#@ include file="$(ProjectDir)DbHelper.ttinclude" #>//------------------------------------------------------------------------------// <博客园-枫伶忆 http://www.cnblogs.com/fenglingyi/>//   此代码由T4模板自动生成//    生成时间 <#=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")#> by 枫伶忆//   对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。//   QQ:549387177// <博客园-枫伶忆 http://www.cnblogs.com/fenglingyi/>//------------------------------------------------------------------------------<#   var dbTableName=config.TableName;  var tableName=config.TableName.Replace("Sys_","")+"Map";  var entity=config.TableName.Replace("Sys_","")+"Entity";  var list= DbHelper.GetDbColumns(config.ConnectionString, config.DbDatabase, config.TableName);  var pk = DbHelper.GetPrimaryKey(list); #>using NFine.Domain.Entity.SystemManage;using System.Data.Entity.ModelConfiguration;namespace NFine.Mapping.SystemManage{    /// <summary>  /// <#=tableName#>  /// </summary>    public class <#=tableName#>:EntityTypeConfiguration<<#=entity#>>  {    public <#=tableName#>()    {     this.ToTable("<#=dbTableName#>");     this.HasKey(t=>t.<#=pk#>);    }  }}

 

6.NFine.Application

<#@ template debug="false" hostspecific="false" language="C#" #><#@ output extension=".cs" #><#@ assembly name="System.Core.dll" #><#@ assembly name="System.Data.dll" #><#@ assembly name="System.Data.DataSetExtensions.dll" #><#@ assembly name="System." #><#@ import namespace="System" #><#@ import namespace="System." #><#@ import namespace="System.Linq" #><#@ import namespace="System.Data" #><#@ import namespace="System.Data.SqlClient" #><#@ import namespace="System.Collections.Generic" #><#@ import namespace="System.IO" #><#@ include file="$(ProjectDir)DbHelper.ttinclude" #>//------------------------------------------------------------------------------// <博客园-枫伶忆 http://www.cnblogs.com/fenglingyi/>//   此代码由T4模板自动生成//    生成时间 <#=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")#> by 枫伶忆//   对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。//   QQ:549387177// <博客园-枫伶忆 http://www.cnblogs.com/fenglingyi/>//------------------------------------------------------------------------------<#   var tableName=config.TableName.Replace("Sys_","")+"App";  var entity=config.TableName.Replace("Sys_","")+"Entity";  var repository=config.TableName.Replace("Sys_","")+"Repository"; #>using System;using System.Collections.Generic;using System.Linq;using System.Text;using NFine.Domain.Entity.SystemManage;using NFine.Domain.IRepository.SystemManage;using NFine.Repository.SystemManage;namespace NFine.Application.SystemManage{    /// <summary>  /// <#=tableName#>  /// </summary>    public class <#=tableName#>  {    private I<#=repository#> service=new <#=repository#>();    public List<<#=entity#>> GetList()    {      return service.IQueryable().ToList();    }    public <#=entity#> GetForm(string keyValue)    {      return service.FindEntity(keyValue);    }    public void Delete(<#=entity#> entity)    {      service.Delete(entity);    }    public void SubmitForm(<#=entity#> entity, string keyValue)    {      if (!string.IsNullOrEmpty(keyValue))      {        entity.Modify(keyValue);        service.Update(entity);      }      else      {        entity.Create();        service.Insert(entity);      }    }  }}

 7.DbHelper.ttinclude 

核心的帮助类

<#+   public class DbHelper  {    #region GetDbTables    public static List<DbTable> GetDbTables(string connectionString, string database, string tables = null)    {      if (!string.IsNullOrEmpty(tables))      {        tables = string.Format(" and obj.name in ('{0}')", tables.Replace(",", "','"));      }      #region SQL      string sql = string.Format(@"SELECT                  obj.name tablename,                  schem.name schemname,                  idx.rows,                  CAST                  (                    CASE                       WHEN (SELECT COUNT(1) FROM sys.indexes WHERE object_id= obj.OBJECT_ID AND is_primary_key=1) >=1 THEN 1                      ELSE 0                    END                   AS BIT) HasPrimaryKey                                       from {0}.sys.objects obj                   inner join {0}.dbo.sysindexes idx on obj.object_id=idx.id and idx.indid<=1                  INNER JOIN {0}.sys.schemas schem ON obj.schema_id=schem.schema_id                  where type='U' {1}                  order by obj.name", database, tables);      #endregion      DataTable dt = GetDataTable(connectionString, sql);      return dt.Rows.Cast<DataRow>().Select(row => new DbTable      {        TableName = row.Field<string>("tablename"),        SchemaName = row.Field<string>("schemname"),        Rows = row.Field<int>("rows"),        HasPrimaryKey = row.Field<bool>("HasPrimaryKey")      }).ToList();    }    #endregion    #region GetDbColumns    public static List<DbColumn> GetDbColumns(string connectionString, string database, string tableName, string schema = "dbo")    {      #region SQL      string sql = string.Format(@"                  WITH indexCTE AS                  (                    SELECT                     ic.column_id,                    ic.index_column_id,                    ic.object_id                      FROM {0}.sys.indexes idx                    INNER JOIN {0}.sys.index_columns ic ON idx.index_id = ic.index_id AND idx.object_id = ic.object_id                    WHERE idx.object_id =OBJECT_ID(@tableName) AND idx.is_primary_key=1                  )                  select                  colm.column_id ColumnID,                  CAST(CASE WHEN indexCTE.column_id IS NULL THEN 0 ELSE 1 END AS BIT) IsPrimaryKey,                  colm.name ColumnName,                  systype.name ColumnType,                  colm.is_identity IsIdentity,                  colm.is_nullable IsNullable,                  cast(colm.max_length as int) ByteLength,                  (                    case                       when systype.name='nvarchar' and colm.max_length>0 then colm.max_length/2                       when systype.name='nchar' and colm.max_length>0 then colm.max_length/2                      when systype.name='ntext' and colm.max_length>0 then colm.max_length/2                       else colm.max_length                    end                  ) CharLength,                  cast(colm.precision as int) Precision,                  cast(colm.scale as int) Scale,                  prop.value Remark                  from {0}.sys.columns colm                  inner join {0}.sys.types systype on colm.system_type_id=systype.system_type_id and colm.user_type_id=systype.user_type_id                  left join {0}.sys.extended_properties prop on colm.object_id=prop.major_id and colm.column_id=prop.minor_id                  LEFT JOIN indexCTE ON colm.column_id=indexCTE.column_id AND colm.object_id=indexCTE.object_id                                      where colm.object_id=OBJECT_ID(@tableName)                  order by colm.column_id", database);      #endregion      SqlParameter param = new SqlParameter("@tableName", SqlDbType.NVarChar, 100) { Value = string.Format("{0}.{1}.{2}", database, schema, tableName) };      DataTable dt = GetDataTable(connectionString, sql, param);      return dt.Rows.Cast<DataRow>().Select(row => new DbColumn()      {        ColumnID = row.Field<int>("ColumnID"),        IsPrimaryKey = row.Field<bool>("IsPrimaryKey"),        ColumnName = row.Field<string>("ColumnName"),        ColumnType = row.Field<string>("ColumnType"),        IsIdentity = row.Field<bool>("IsIdentity"),        IsNullable = row.Field<bool>("IsNullable"),        ByteLength = row.Field<int>("ByteLength"),        CharLength = row.Field<int>("CharLength"),        Scale = row.Field<int>("Scale"),        Remark = row["Remark"].ToString()      }).ToList();    }    #endregion    #region GetDataTable    public static DataTable GetDataTable(string connectionString, string commandText, params SqlParameter[] parms)    {      using (SqlConnection connection = new SqlConnection(connectionString))      {        SqlCommand command = connection.CreateCommand();        command.CommandText = commandText;        command.Parameters.AddRange(parms);        SqlDataAdapter adapter = new SqlDataAdapter(command);        DataTable dt = new DataTable();        adapter.Fill(dt);        return dt;      }    }    #endregion    #region GetPrimaryKey    public static string GetPrimaryKey(List<DbColumn> dbColumns)    {      string primaryKey = string.Empty;      if (dbColumns!=null&&dbColumns.Count>0)      {        foreach (var item in dbColumns)        {          if (item.IsPrimaryKey==true)          {            primaryKey = item.ColumnName;          }        }      }      return primaryKey;    }    #endregion  }  #region DbTable  /// <summary>  /// 表结构  /// </summary>  public sealed class DbTable  {    /// <summary>    /// 表名称    /// </summary>    public string TableName { get; set; }    /// <summary>    /// 表的架构    /// </summary>    public string SchemaName { get; set; }    /// <summary>    /// 表的记录数    /// </summary>    public int Rows { get; set; }    /// <summary>    /// 是否含有主键    /// </summary>    public bool HasPrimaryKey { get; set; }  }  #endregion  #region DbColumn  /// <summary>  /// 表字段结构  /// </summary>  public sealed class DbColumn  {    /// <summary>    /// 字段ID    /// </summary>    public int ColumnID { get; set; }    /// <summary>    /// 是否主键    /// </summary>    public bool IsPrimaryKey { get; set; }    /// <summary>    /// 字段名称    /// </summary>    public string ColumnName { get; set; }    /// <summary>    /// 字段类型    /// </summary>    public string ColumnType { get; set; }    /// <summary>    /// 数据库类型对应的C#类型    /// </summary>    public string CSharpType    {      get      {        return SqlServerDbTypeMap.MapCsharpType(ColumnType);      }    }    /// <summary>    ///     /// </summary>    public Type CommonType    {      get      {        return SqlServerDbTypeMap.MapCommonType(ColumnType);      }    }    /// <summary>    /// 字节长度    /// </summary>    public int ByteLength { get; set; }    /// <summary>    /// 字符长度    /// </summary>    public int CharLength { get; set; }    /// <summary>    /// 小数位    /// </summary>    public int Scale { get; set; }    /// <summary>    /// 是否自增列    /// </summary>    public bool IsIdentity { get; set; }    /// <summary>    /// 是否允许空    /// </summary>    public bool IsNullable { get; set; }    /// <summary>    /// 描述    /// </summary>    public string Remark { get; set; }  }  #endregion  #region SqlServerDbTypeMap  public class SqlServerDbTypeMap  {    public static string MapCsharpType(string dbtype)    {      if (string.IsNullOrEmpty(dbtype)) return dbtype;      dbtype = dbtype.ToLower();      string csharpType = "object";      switch (dbtype)      {        case "bigint": csharpType = "long"; break;        case "binary": csharpType = "byte[]"; break;        case "bit": csharpType = "bool"; break;        case "char": csharpType = "string"; break;        case "date": csharpType = "DateTime"; break;        case "datetime": csharpType = "DateTime"; break;        case "datetime2": csharpType = "DateTime"; break;        case "datetimeoffset": csharpType = "DateTimeOffset"; break;        case "decimal": csharpType = "decimal"; break;        case "float": csharpType = "double"; break;        case "image": csharpType = "byte[]"; break;        case "int": csharpType = "int"; break;        case "money": csharpType = "decimal"; break;        case "nchar": csharpType = "string"; break;        case "ntext": csharpType = "string"; break;        case "numeric": csharpType = "decimal"; break;        case "nvarchar": csharpType = "string"; break;        case "real": csharpType = "Single"; break;        case "smalldatetime": csharpType = "DateTime"; break;        case "smallint": csharpType = "short"; break;        case "smallmoney": csharpType = "decimal"; break;        case "sql_variant": csharpType = "object"; break;        case "sysname": csharpType = "object"; break;        case "text": csharpType = "string"; break;        case "time": csharpType = "TimeSpan"; break;        case "timestamp": csharpType = "byte[]"; break;        case "tinyint": csharpType = "byte"; break;        case "uniqueidentifier": csharpType = "Guid"; break;        case "varbinary": csharpType = "byte[]"; break;        case "varchar": csharpType = "string"; break;        case "": csharpType = "string"; break;        default: csharpType = "object"; break;      }      return csharpType;    }    public static Type MapCommonType(string dbtype)    {      if (string.IsNullOrEmpty(dbtype)) return Type.Missing.GetType();      dbtype = dbtype.ToLower();      Type commonType = typeof(object);      switch (dbtype)      {        case "bigint": commonType = typeof(long); break;        case "binary": commonType = typeof(byte[]); break;        case "bit": commonType = typeof(bool); break;        case "char": commonType = typeof(string); break;        case "date": commonType = typeof(DateTime); break;        case "datetime": commonType = typeof(DateTime); break;        case "datetime2": commonType = typeof(DateTime); break;        case "datetimeoffset": commonType = typeof(DateTimeOffset); break;        case "decimal": commonType = typeof(decimal); break;        case "float": commonType = typeof(double); break;        case "image": commonType = typeof(byte[]); break;        case "int": commonType = typeof(int); break;        case "money": commonType = typeof(decimal); break;        case "nchar": commonType = typeof(string); break;        case "ntext": commonType = typeof(string); break;        case "numeric": commonType = typeof(decimal); break;        case "nvarchar": commonType = typeof(string); break;        case "real": commonType = typeof(Single); break;        case "smalldatetime": commonType = typeof(DateTime); break;        case "smallint": commonType = typeof(short); break;        case "smallmoney": commonType = typeof(decimal); break;        case "sql_variant": commonType = typeof(object); break;        case "sysname": commonType = typeof(object); break;        case "text": commonType = typeof(string); break;        case "time": commonType = typeof(TimeSpan); break;        case "timestamp": commonType = typeof(byte[]); break;        case "tinyint": commonType = typeof(byte); break;        case "uniqueidentifier": commonType = typeof(Guid); break;        case "varbinary": commonType = typeof(byte[]); break;        case "varchar": commonType = typeof(string); break;        case "": commonType = typeof(string); break;        default: commonType = typeof(object); break;      }      return commonType;    }  }  #endregion #><#+  public class config  {    public static readonly string ConnectionString = "Data Source=(local);Initial Catalog=NFineBase;User ID=sa;Password=hjf19870810;";    public static readonly string DbDatabase = "NFineBase";    public static readonly string TableName = "Sys_Test";  }#>

8.ModelAuto.ttinclude

用来生成多个单独的类文件。

<#@ assembly name="System.Core"#><#@ assembly name="EnvDTE"#><#@ import namespace="System.Collections.Generic"#><#@ import namespace="System.IO"#><#@ import namespace="System.Text"#><#@ import namespace="Microsoft.VisualStudio.TextTemplating"#><#+class Manager{  public struct Block {    public String Name;    public int Start, Length;  }  public List<Block> blocks = new List<Block>();  public Block currentBlock;  public Block footerBlock = new Block();  public Block headerBlock = new Block();  public ITextTemplatingEngineHost host;  public ManagementStrategy strategy;  public StringBuilder template;  public String OutputPath { get; set; }  public Manager(ITextTemplatingEngineHost host, StringBuilder template, bool commonHeader) {    this.host = host;    this.template = template;    OutputPath = String.Empty;    strategy = ManagementStrategy.Create(host);  }  public void StartBlock(String name) {    currentBlock = new Block { Name = name, Start = template.Length };  }  public void StartFooter() {    footerBlock.Start = template.Length;  }  public void EndFooter() {    footerBlock.Length = template.Length - footerBlock.Start;  }  public void StartHeader() {    headerBlock.Start = template.Length;  }  public void EndHeader() {    headerBlock.Length = template.Length - headerBlock.Start;  }    public void EndBlock() {    currentBlock.Length = template.Length - currentBlock.Start;    blocks.Add(currentBlock);  }  public void Process(bool split) {    String header = template.ToString(headerBlock.Start, headerBlock.Length);    String footer = template.ToString(footerBlock.Start, footerBlock.Length);    blocks.Reverse();    foreach(Block block in blocks) {      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);      }    }  }}class ManagementStrategy{  internal static ManagementStrategy Create(ITextTemplatingEngineHost host) {    return (host is IServiceProvider) ? new VSManagementStrategy(host) : new ManagementStrategy(host);  }  internal ManagementStrategy(ITextTemplatingEngineHost host) { }  internal virtual void CreateFile(String fileName, String content) {    File.WriteAllText(fileName, content);  }  internal virtual void DeleteFile(String fileName) {    if (File.Exists(fileName))      File.Delete(fileName);  }}class VSManagementStrategy : ManagementStrategy{  private EnvDTE.ProjectItem templateProjectItem;  internal VSManagementStrategy(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 void CreateFile(String fileName, String content) {    base.CreateFile(fileName, content);    ((EventHandler)delegate { templateProjectItem.ProjectItems.AddFromFile(fileName); }).BeginInvoke(null, null, null, null);  }  internal override void DeleteFile(String fileName) {    ((EventHandler)delegate { FindAndDeleteFile(fileName); }).BeginInvoke(null, null, null, null);  }  private void FindAndDeleteFile(String fileName) {    foreach(EnvDTE.ProjectItem projectItem in templateProjectItem.ProjectItems) {      if (projectItem.get_FileNames(0) == fileName) {        projectItem.Delete();        return;      }    }  }}#>

View Code

模板在此下载。

1.T4语法快速入门

2.T4模板根据DB生成实体类

3.NFine框架的T4模板