使用T4模板生成POCO類

来源:http://www.cnblogs.com/jiekzou/archive/2017/02/17/6410719.html
-Advertisement-
Play Games

為什麼叫T4?因為簡寫為4個T。 T4(Text Template Transformation Toolkit)是微軟官方在VisualStudio 2008中開始使用的代碼生成引擎。在 Visual Studio 中,“T4 文本模板”是由一些文本塊和控制邏輯組成的混合模板,它可以生成文本文件。 ...


為什麼叫T4?因為簡寫為4個T。

T4(Text Template Transformation Toolkit)是微軟官方在VisualStudio 2008中開始使用的代碼生成引擎。在 Visual Studio 中,“T4 文本模板”是由一些文本塊和控制邏輯組成的混合模板,它可以生成文本文件。 在 Visual C# 或 Visual Basic 中,控制邏輯編寫為程式代碼的片段。生成的文件可以是任何類型的文本,例如網頁、資源文件或任何語言的程式源代碼。現在的VS中只要與代碼生成相關的場景基本上都能找T4的身影,比如MVC的視圖模板,Entity Framwork的DataContext模板等等。

若論靈活性,各種代碼生成工具還真不如T4模板。

在VS2013種預設沒有了T4模板,取而代之的是文本模板,但是他們的尾碼名都是.tt。我們可以通過NuGet安裝T4模板。

安裝之後,我們在項目中新建項的時候,在VS模板中就多了兩項和T4模板相關的模板。

當我們在新建的T4模板中進行代碼編寫的時候,預設是沒有智能提示的,我們需要再安裝一個T4Editor的VS插件tangibleT4EditorPlusModellingToolsVS2013.msi。

下載地址:

https://marketplace.visualstudio.com/items?itemName=tangibleengineeringGmbH.tangibleT4Editor230plusmodelingtoolsforVS2013

 由於我這裡用的是VS2013,所以按照13的插件,安裝插件時先關閉VS,安裝完成之後在T4模板中編寫代碼時就有了智能提示了。

關於T4模板的詳細講解,大家可以參照一下博客文章:

你必須懂的 T4 模板:體系架構

(譯)理解 T4 模板:<#@ parameter #> 指令

我這裡要說的是,如何在項目中替代其它的代碼工具來使用,比如說,自動生成資料庫中的POCO類。

 思路:1、我們要查詢中資料庫中的表和欄位。2、根據數據表名才,將其生成多個POCO類文件

How to do?

開發環境:VS2013

準備工作:添加必須的程式集引用

在自己電腦上面用everythin找到Microsoft.VisualStudio.TextTemplating.Interfaces.10.0.dll,然後添加引用,如果沒有,你就網上下載一個。

方式一

 1、添加一個T4模板文件DbHelper,將其尾碼修改為.ttinclude,因為我是將其作為內嵌的T4文件,不修改擴展名的話,會將其當成T4模板文件進行生成。

<#+
    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 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 "xml": 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 "xml": commonType = typeof(string); break;
                default: commonType = typeof(object); break;
            }
            return commonType;
        }
    }
    #endregion
    

#>
View Code

上面的代碼就是查詢資料庫中的表和欄位。

2、同樣添加另一個T4模板文件,並修改尾碼名Manager.ttinclude

<#@ assembly name="System.Data.Linq"
#><#@ assembly name="EnvDTE"
#><#@ assembly name="System.Xml"
#><#@ assembly name="System.Xml.Linq"
#><#@ import namespace="System.Collections.Generic"
#><#@ import namespace="System.IO"
#><#@ import namespace="System.Text"
#><#@ import namespace="Microsoft.VisualStudio.TextTemplating"
#><#+
// https://raw.github.com/damieng/DamienGKit
// http://damieng.com/blog/2009/11/06/multiple-outputs-from-t4-made-easy-revisited

// Manager class records the various blocks so it can split them up
class Manager {
    private class Block {
        public String Name;
        public int Start, Length;
        public bool IncludeInDefault;
    }

    private Block currentBlock;
    private readonly List<Block> files = new List<Block>();
    private readonly Block footer = new Block();
    private readonly Block header = new Block();
    private readonly ITextTemplatingEngineHost host;
    private readonly StringBuilder template;
    protected readonly List<String> generatedFileNames = new List<String>();

    public static Manager Create(ITextTemplatingEngineHost host, StringBuilder template) {
        return (host is IServiceProvider) ? new VSManager(host, template) : new Manager(host, template);
    }

    public void StartNewFile(String name) {
        if (name == null)
            throw new ArgumentNullException("name");
        CurrentBlock = new Block { Name = name };
    }

    public void StartFooter(bool includeInDefault = true) {
        CurrentBlock = footer;
        footer.IncludeInDefault = includeInDefault;
    }

    public void StartHeader(bool includeInDefault = true) {
        CurrentBlock = header;
        header.IncludeInDefault = includeInDefault;
    }

    public void EndBlock() {
        if (CurrentBlock == null)
            return;
        CurrentBlock.Length = template.Length - CurrentBlock.Start;
        if (CurrentBlock != header && CurrentBlock != footer)
            files.Add(CurrentBlock);
        currentBlock = null;
    }

    public virtual void Process(bool split, bool sync = true) {
        if (split) {
            EndBlock();
            String headerText = template.ToString(header.Start, header.Length);
            String footerText = template.ToString(footer.Start, footer.Length);
            String outputPath = Path.GetDirectoryName("host.TemplateFile");
            files.Reverse();
            if (!footer.IncludeInDefault)
                template.Remove(footer.Start, footer.Length);
            foreach(Block block in files) {
                String fileName = Path.Combine(outputPath, block.Name);
                String content = headerText + template.ToString(block.Start, block.Length) + footerText;
                generatedFileNames.Add(fileName);
                CreateFile(fileName, content);
                template.Remove(block.Start, block.Length);
            }
            if (!header.IncludeInDefault)
                template.Remove(header.Start, header.Length);
        }
    }

    protected virtual void CreateFile(String fileName, String content) {
        if (IsFileContentDifferent(fileName, content))
            File.WriteAllText(fileName, content);
    }

    public virtual String GetCustomToolNamespace(String fileName) {
        return null;
    }

    public virtual String DefaultProjectNamespace {
        get { return null; }
    }

    protected bool IsFileContentDifferent(String fileName, String newContent) {
        return !(File.Exists(fileName) && File.ReadAllText(fileName) == newContent);
    }

    private Manager(ITextTemplatingEngineHost host, StringBuilder template) {
        this.host = host;
        this.template = template;
    }

    private Block CurrentBlock {
        get { return currentBlock; }
        set {
            if (CurrentBlock != null)
                EndBlock();
            if (value != null)
                value.Start = template.Length;
            currentBlock =
              
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 格式:cut [參數] 文本 參數:-d [分隔符] 指定分割符,預設為TAB -f 指定顯示的列數 -c 單位改為字元 示例:查看系統中所有的用戶名 ...
  • 我校的課程真是跟不上時代發展,甚至還在教授8051/8052單片機的內容,於是不甘寂寞的我就自己踏入了STM32單片機的坑…… 首先,我現在大二,剛學完模擬電子技術,還沒有學習數字電路技術,於是自學單片機開發會有一定困難,而我校要到大三才能開放單片機課程,這就很有趣了,我不得不去啃一些完全沒見過的玩 ...
  • 等待隊列 是內核中實現進程調度的一個十分重要的數據結構,其任務是維護一個鏈表,鏈表中每一個節點都是一個PCB(進程式控制制塊), 內核會將PCB掛在等待隊列中的所有進程都調度為睡眠狀態,直到某個喚醒的條件發生 。應用層的阻塞IO與非阻塞IO的使用我已經在 "Linux I/O多路復用" 一文中討論過了, ...
  • 簡介 RabbitMQ:一個消息系統,基於 AMQP 系統協議。 優點:健壯、使用簡單、開源和支持各種流行的語言等。 MQ(Message Queue):消息隊列的簡稱,是一種應用程式之間的通信機制。 用途:將無需立即回調獲取返回結果,並且耗時的操作,使用非同步處理的方式提高伺服器的吞吐量及性能。 ...
  • 初步應用vs2012這軟體,語言選擇c# , 框架選擇4(不要選擇最前和太後的框架)然後改個名字和保存路徑點確定就行了。 在main函數中寫代碼,大括弧裡面。 首先是最基本的輸入與輸出: Console.WriteLine(");//直接會輸出引號裡面的內容(如果直接寫入Write的話就不會換行。) ...
  • 電子面單開發流程 服務程式 生成單號,改變三個表: 抓類型表,抓取未處理的充值記錄->根據類型取面單類型表的最大單號(判斷是否在起始和結束之間,並設置郵件或者簡訊預警 )->根據單號規則和充值的數量生成單號明細入單號明細表,改變充值記錄的處理狀態 改變面單類型最大單號(事務提交)。 ...
  • 經過本周的努力,昨晚終於完成OSS.Social微信項目的標準庫支持,當前項目你已經可以同時在.net framework和.net core 中進行調用,調用方法也發生了部分變化,這裡我簡單分享下,主要包含下邊幾個部分: · 移植後的變化 · 和OSS.Common,OSS.Http關係 · 非同步 ...
  • #define aaa //放在代碼最前面 int a = 1; a = a + 1; #if !aaa {a = a + 1;}#elif !aaaaa {a=a+11;}#endif Console.WriteLine(a); Console.ReadKey(); 據說與版本有關 ,#undef ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...