從壹開始先後端分離 [.netCore 填坑 ] 三十二║ 四種方法快速實現項目的半自動化搭建

更新

一、更新小夥伴 @大齡Giser 提出好點子:試試VS的插件擴展:VSIX、ItemProject等,將T4模板給製做插件,這裏先記下,有懂的小夥伴能夠本身先試試,我會在之後更新。html

二、感謝小夥伴  @博客園董事長 的測試和指正,本文 T4 模板已經支持 Oraclemysql

三、再次感謝小夥伴 @大齡Giser  關於 使用VSIX+ProjectTemplate建立項目模板,提供開源支持:http://www.javashuo.com/article/p-knswooks-bx.htmlc++

四、感謝羣小夥伴 @jamee1696  提供技術支持,本文 T4 模板已經支持 Mysqlgit

五、若是感受 Blog.Core.Framework 層比較笨重,我單寫了一個簡單的生成框架文件的接口,能夠查看 DbFirstController.cs 【推薦使用】github

緣起

哈嘍你們週二好呀,這個國慶過的真是懶洋洋呀,不知道你們的學習動力咋樣了,剛一上班本人手中的項目也增長了,可是仍是要抽出時間學習噠,爲了避免讓老闆大大每天催,因此更新會慢點兒 [ 哭笑 ] :bowtie:,不過在個人推薦下,公司下一個項目要我負責先後端分離,終於能夠將這些派上用場了,中間的坑也會在之後的文章中,慢慢補充出來。sql

這幾天簡單想了想,尚未想好要開什麼系列,就想到QQ羣裏有小夥伴問的較多的一些問題以及前邊系列文章中的提到的,可是沒有深刻講到的,再填一下坑,這樣纔是完整的嘛,你們要是看到以前的有任何不清楚的,或者想擴展的,能夠在羣裏說一下,或者留言,我都會說到的。今天呢,就說說若是半自動化搭建項目,這個坑來自於以前的項目搭建文章《框架之六 || API項目總體搭建 6.1 倉儲模式》的伏筆之一 —— 如何使用 T4 模板搭建項目。固然,咱們不只是簡單說說實體類的建立,也會橫向和縱向的討論下,一個項目如何經過代碼實現半自動化搭建。數據庫

說到這裏你們應該已經明白了這篇文章的寫做意圖,就是搭建項目的問題,相信你們已經開發了幾年了,都有本身的一套行之有效的辦法或者是經驗,固然這裏就不說付費的了,付費的框架何其多,好比迪西客,普元或者力軟等等,這都是好用的功能強大的付費框架,既然說技術,就不說付費的,我們本身寫,這裏簡單歸納下今天要說到的:windows

0、手動粘貼複製 —— 可能如今還有小夥伴在用這個辦法,效率是真的很低,雖然我偶爾也用哈哈,這裏就不說了後端

一、動軟代碼生成器 —— 這個我入門的時候使用的神器,用了很久服務器

二、經過 VSTO 來編寫 Excel ,實現每一層的代碼設計 —— 我沒用過,可是見過,一個不錯的思路

三、T4 模板 —— 這個是我這兩年遇到的又一個神器,也是一直使用的,強烈推薦的

四、SqlSuagr(ORM)—— 自封裝的一套邏輯,固然其餘ORM也有,好比EF就很好

五、VSIX 擴展插件 —— 新的處理方案

今天我們這幾個方法都會說到,主要仍是說一下經過 T4 模板,來把咱們的總體框架半自動化起來。最終的效果截圖是這樣的:

框架截圖

 

1、動軟代碼生成器搭建總體項目框架

相信不少的小夥伴應該使用過這個工具,仍是很不錯的,我也是用了有一段時間,雖然很小,可是功能確實很豐富,不管是生成實體類,仍是生成簡單三層,仍是工廠模式等等,均可以使用,不只支持單個表文件的操做,也支持整個數據庫的批量生成,這裏具體的不作敘述,由於不是本篇文章的重點,這裏簡單的說下使用方法以及效果圖:

一、安裝與使用

地址:http://www.maticsoft.com/download.aspx

安裝仍是很簡單的,就是普通的 next ,想用的能夠試試,這裏就不作敘述了。

安裝成功後,咱們能夠看到,經過鏈接相應的服務器,找到適當的數據庫,就能夠操做了,主要仍是經過一套 cmt 模板來生成對應的 .cs 類文件,這些模板咱們可使用系統自帶的(好比工廠模式模板),也能夠自定義編輯,以知足咱們不一樣項目的具體需求,我這裏就演示下,如何把個人博客數據庫(仍是我們一直用的這個數據庫),生成簡單工程框架。

 

 通過短暫的等待後,咱們的所有框架就這麼出來了

 

固然這些後綴名等均可以配置,這裏就不細說了,我們隨便看一下數據訪問層的內容:

/**  版本信息模板在安裝目錄下,可自行修改。
* BlogArticle.cs
*
* 功 能: N/A
* 類 名: BlogArticle
*
* Ver    變動日期             負責人  變動內容
* ───────────────────────────────────
* V0.01  2018/10/8 23:46:56   N/A    第一版
*
* Copyright (c) 2012 Maticsoft Corporation. All rights reserved.
*┌──────────────────────────────────┐
*│ 此技術信息爲本公司機密信息,未經本公司書面贊成禁止向第三方披露. │
*│ 版權全部:動軟卓越(北京)科技有限公司              │
*└──────────────────────────────────┘
*/
using System;
using System.Data;
using System.Text;
using System.Data.SqlClient;
using Maticsoft.IDAL;
using Maticsoft.DBUtility;//Please add references
namespace Maticsoft.SQLServerDAL
{
    /// <summary>
    /// 數據訪問類:BlogArticle
    /// </summary>
    public partial class BlogArticle:IBlogArticle
    {
        public BlogArticle()
        {}
        #region  BasicMethod

        /// <summary>
        /// 獲得最大ID
        /// </summary>
        public int GetMaxId()
        {
        return DbHelperSQL.GetMaxID("bID", "BlogArticle"); 
        }

        /// <summary>
        /// 是否存在該記錄
        /// </summary>
        public bool Exists(int bID)
        {
            StringBuilder strSql=new StringBuilder();
            strSql.Append("select count(1) from BlogArticle");
            strSql.Append(" where bID=@bID");
            SqlParameter[] parameters = {
                    new SqlParameter("@bID", SqlDbType.Int,4)
            };
            parameters[0].Value = bID;

            return DbHelperSQL.Exists(strSql.ToString(),parameters);
        }


        /// <summary>
        /// 增長一條數據
        /// </summary>
        public int Add(Maticsoft.Model.BlogArticle model)
        {
            StringBuilder strSql=new StringBuilder();
            strSql.Append("insert into BlogArticle(");
            strSql.Append("bsubmitter,btitle,bcategory,bcontent,btraffic,bcommentNum,bUpdateTime,bCreateTime,bRemark)");
            strSql.Append(" values (");
            strSql.Append("@bsubmitter,@btitle,@bcategory,@bcontent,@btraffic,@bcommentNum,@bUpdateTime,@bCreateTime,@bRemark)");
            strSql.Append(";select @@IDENTITY");
            SqlParameter[] parameters = {
                    new SqlParameter("@bsubmitter", SqlDbType.NVarChar,60),
                    new SqlParameter("@btitle", SqlDbType.NVarChar,256),
                    new SqlParameter("@bcategory", SqlDbType.NVarChar,-1),
                    new SqlParameter("@bcontent", SqlDbType.Text),
                    new SqlParameter("@btraffic", SqlDbType.Int,4),
                    new SqlParameter("@bcommentNum", SqlDbType.Int,4),
                    new SqlParameter("@bUpdateTime", SqlDbType.DateTime),
                    new SqlParameter("@bCreateTime", SqlDbType.DateTime),
                    new SqlParameter("@bRemark", SqlDbType.NVarChar,-1)};
            parameters[0].Value = model.bsubmitter;
            parameters[1].Value = model.btitle;
            parameters[2].Value = model.bcategory;
            parameters[3].Value = model.bcontent;
            parameters[4].Value = model.btraffic;
            parameters[5].Value = model.bcommentNum;
            parameters[6].Value = model.bUpdateTime;
            parameters[7].Value = model.bCreateTime;
            parameters[8].Value = model.bRemark;

            object obj = DbHelperSQL.GetSingle(strSql.ToString(),parameters);
            if (obj == null)
            {
                return 0;
            }
            else
            {
                return Convert.ToInt32(obj);
            }
        }
        /// <summary>
        /// 更新一條數據
        /// </summary>
        public bool Update(Maticsoft.Model.BlogArticle model)
        {
            StringBuilder strSql=new StringBuilder();
            strSql.Append("update BlogArticle set ");
            strSql.Append("bsubmitter=@bsubmitter,");
            strSql.Append("btitle=@btitle,");
            strSql.Append("bcategory=@bcategory,");
            strSql.Append("bcontent=@bcontent,");
            strSql.Append("btraffic=@btraffic,");
            strSql.Append("bcommentNum=@bcommentNum,");
            strSql.Append("bUpdateTime=@bUpdateTime,");
            strSql.Append("bCreateTime=@bCreateTime,");
            strSql.Append("bRemark=@bRemark");
            strSql.Append(" where bID=@bID");
            SqlParameter[] parameters = {
                    new SqlParameter("@bsubmitter", SqlDbType.NVarChar,60),
                    new SqlParameter("@btitle", SqlDbType.NVarChar,256),
                    new SqlParameter("@bcategory", SqlDbType.NVarChar,-1),
                    new SqlParameter("@bcontent", SqlDbType.Text),
                    new SqlParameter("@btraffic", SqlDbType.Int,4),
                    new SqlParameter("@bcommentNum", SqlDbType.Int,4),
                    new SqlParameter("@bUpdateTime", SqlDbType.DateTime),
                    new SqlParameter("@bCreateTime", SqlDbType.DateTime),
                    new SqlParameter("@bRemark", SqlDbType.NVarChar,-1),
                    new SqlParameter("@bID", SqlDbType.Int,4)};
            parameters[0].Value = model.bsubmitter;
            parameters[1].Value = model.btitle;
            parameters[2].Value = model.bcategory;
            parameters[3].Value = model.bcontent;
            parameters[4].Value = model.btraffic;
            parameters[5].Value = model.bcommentNum;
            parameters[6].Value = model.bUpdateTime;
            parameters[7].Value = model.bCreateTime;
            parameters[8].Value = model.bRemark;
            parameters[9].Value = model.bID;

            int rows=DbHelperSQL.ExecuteSql(strSql.ToString(),parameters);
            if (rows > 0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// 刪除一條數據
        /// </summary>
        public bool Delete(int bID)
        {
            
            StringBuilder strSql=new StringBuilder();
            strSql.Append("delete from BlogArticle ");
            strSql.Append(" where bID=@bID");
            SqlParameter[] parameters = {
                    new SqlParameter("@bID", SqlDbType.Int,4)
            };
            parameters[0].Value = bID;

            int rows=DbHelperSQL.ExecuteSql(strSql.ToString(),parameters);
            if (rows > 0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// 批量刪除數據
        /// </summary>
        public bool DeleteList(string bIDlist )
        {
            StringBuilder strSql=new StringBuilder();
            strSql.Append("delete from BlogArticle ");
            strSql.Append(" where bID in ("+bIDlist + ")  ");
            int rows=DbHelperSQL.ExecuteSql(strSql.ToString());
            if (rows > 0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }


        /// <summary>
        /// 獲得一個對象實體
        /// </summary>
        public Maticsoft.Model.BlogArticle GetModel(int bID)
        {
            
            StringBuilder strSql=new StringBuilder();
            strSql.Append("select  top 1 bID,bsubmitter,btitle,bcategory,bcontent,btraffic,bcommentNum,bUpdateTime,bCreateTime,bRemark from BlogArticle ");
            strSql.Append(" where bID=@bID");
            SqlParameter[] parameters = {
                    new SqlParameter("@bID", SqlDbType.Int,4)
            };
            parameters[0].Value = bID;

            Maticsoft.Model.BlogArticle model=new Maticsoft.Model.BlogArticle();
            DataSet ds=DbHelperSQL.Query(strSql.ToString(),parameters);
            if(ds.Tables[0].Rows.Count>0)
            {
                return DataRowToModel(ds.Tables[0].Rows[0]);
            }
            else
            {
                return null;
            }
        }


        /// <summary>
        /// 獲得一個對象實體
        /// </summary>
        public Maticsoft.Model.BlogArticle DataRowToModel(DataRow row)
        {
            Maticsoft.Model.BlogArticle model=new Maticsoft.Model.BlogArticle();
            if (row != null)
            {
                if(row["bID"]!=null && row["bID"].ToString()!="")
                {
                    model.bID=int.Parse(row["bID"].ToString());
                }
                if(row["bsubmitter"]!=null)
                {
                    model.bsubmitter=row["bsubmitter"].ToString();
                }
                if(row["btitle"]!=null)
                {
                    model.btitle=row["btitle"].ToString();
                }
                if(row["bcategory"]!=null)
                {
                    model.bcategory=row["bcategory"].ToString();
                }
                if(row["bcontent"]!=null)
                {
                    model.bcontent=row["bcontent"].ToString();
                }
                if(row["btraffic"]!=null && row["btraffic"].ToString()!="")
                {
                    model.btraffic=int.Parse(row["btraffic"].ToString());
                }
                if(row["bcommentNum"]!=null && row["bcommentNum"].ToString()!="")
                {
                    model.bcommentNum=int.Parse(row["bcommentNum"].ToString());
                }
                if(row["bUpdateTime"]!=null && row["bUpdateTime"].ToString()!="")
                {
                    model.bUpdateTime=DateTime.Parse(row["bUpdateTime"].ToString());
                }
                if(row["bCreateTime"]!=null && row["bCreateTime"].ToString()!="")
                {
                    model.bCreateTime=DateTime.Parse(row["bCreateTime"].ToString());
                }
                if(row["bRemark"]!=null)
                {
                    model.bRemark=row["bRemark"].ToString();
                }
            }
            return model;
        }

        /// <summary>
        /// 得到數據列表
        /// </summary>
        public DataSet GetList(string strWhere)
        {
            StringBuilder strSql=new StringBuilder();
            strSql.Append("select bID,bsubmitter,btitle,bcategory,bcontent,btraffic,bcommentNum,bUpdateTime,bCreateTime,bRemark ");
            strSql.Append(" FROM BlogArticle ");
            if(strWhere.Trim()!="")
            {
                strSql.Append(" where "+strWhere);
            }
            return DbHelperSQL.Query(strSql.ToString());
        }

        /// <summary>
        /// 得到前幾行數據
        /// </summary>
        public DataSet GetList(int Top,string strWhere,string filedOrder)
        {
            StringBuilder strSql=new StringBuilder();
            strSql.Append("select ");
            if(Top>0)
            {
                strSql.Append(" top "+Top.ToString());
            }
            strSql.Append(" bID,bsubmitter,btitle,bcategory,bcontent,btraffic,bcommentNum,bUpdateTime,bCreateTime,bRemark ");
            strSql.Append(" FROM BlogArticle ");
            if(strWhere.Trim()!="")
            {
                strSql.Append(" where "+strWhere);
            }
            strSql.Append(" order by " + filedOrder);
            return DbHelperSQL.Query(strSql.ToString());
        }

        /// <summary>
        /// 獲取記錄總數
        /// </summary>
        public int GetRecordCount(string strWhere)
        {
            StringBuilder strSql=new StringBuilder();
            strSql.Append("select count(1) FROM BlogArticle ");
            if(strWhere.Trim()!="")
            {
                strSql.Append(" where "+strWhere);
            }
            object obj = DbHelperSQL.GetSingle(strSql.ToString());
            if (obj == null)
            {
                return 0;
            }
            else
            {
                return Convert.ToInt32(obj);
            }
        }
        /// <summary>
        /// 分頁獲取數據列表
        /// </summary>
        public DataSet GetListByPage(string strWhere, string orderby, int startIndex, int endIndex)
        {
            StringBuilder strSql=new StringBuilder();
            strSql.Append("SELECT * FROM ( ");
            strSql.Append(" SELECT ROW_NUMBER() OVER (");
            if (!string.IsNullOrEmpty(orderby.Trim()))
            {
                strSql.Append("order by T." + orderby );
            }
            else
            {
                strSql.Append("order by T.bID desc");
            }
            strSql.Append(")AS Row, T.*  from BlogArticle T ");
            if (!string.IsNullOrEmpty(strWhere.Trim()))
            {
                strSql.Append(" WHERE " + strWhere);
            }
            strSql.Append(" ) TT");
            strSql.AppendFormat(" WHERE TT.Row between {0} and {1}", startIndex, endIndex);
            return DbHelperSQL.Query(strSql.ToString());
        }

        /*
        /// <summary>
        /// 分頁獲取數據列表
        /// </summary>
        public DataSet GetList(int PageSize,int PageIndex,string strWhere)
        {
            SqlParameter[] parameters = {
                    new SqlParameter("@tblName", SqlDbType.VarChar, 255),
                    new SqlParameter("@fldName", SqlDbType.VarChar, 255),
                    new SqlParameter("@PageSize", SqlDbType.Int),
                    new SqlParameter("@PageIndex", SqlDbType.Int),
                    new SqlParameter("@IsReCount", SqlDbType.Bit),
                    new SqlParameter("@OrderType", SqlDbType.Bit),
                    new SqlParameter("@strWhere", SqlDbType.VarChar,1000),
                    };
            parameters[0].Value = "BlogArticle";
            parameters[1].Value = "bID";
            parameters[2].Value = PageSize;
            parameters[3].Value = PageIndex;
            parameters[4].Value = 0;
            parameters[5].Value = 0;
            parameters[6].Value = strWhere;    
            return DbHelperSQL.RunProcedure("UP_GetRecordByPage",parameters,"ds");
        }*/

        #endregion  BasicMethod
        #region  ExtensionMethod

        #endregion  ExtensionMethod
    }
}
View Code

 提示:若是你不想下載該軟件,又想看看具體的代碼,我已經提交到我們的git 了,在wwwroot 文件夾中,你們能夠看看

截圖

 

 

打開看一下,基本的 CURD 方法都有,也有一些存儲過程的調用等,並且能夠自定義擴展,不得不說是一個神器,若是要開發 ADO.NET 多層,這個方法也不失爲一個好的方案。

優勢你們都看到了,快速,內容簡潔豐富,各類存儲過程分頁方法很方便,不言而喻;

可是缺點也是有的,最大的就是不能像其餘ORM框架那樣,實現 Code First ,只能單純的講數據庫信息提取出來;並且在編輯模板方面也沒有 T4 那麼容易操做,修改模板代碼不是很方便,學習的難度稍微大了一些。

總結:若是不想用 T4 模板手動寫模板代碼,又不想引入框架,只想用 ADO.NET 搭建多層框架,動軟代碼生成器是一個不錯的選擇。

 

2、經過 VSTO 編寫 Excel 來搭建總體項目框架

一、什麼是VSTO?

 VSTO(Visual Studio Tools For Office)就像名字同樣,是Visual Studio開發Office的工具集。只是一套工具,用於簡化.NET的Office開發。可以生成com組件或者標準dll的都能開發Office,好比c/c++,VB6,Delphi等等。原生.NET固然也能夠。微軟以爲.net開發Office不夠方便,VSTO便誕生了。

1.決定要用.NET開發Office

2.在全部.NET開發Office的途徑(原始,各類工具)中,選擇了VSTO

二、如何新建一個 VSTO 項目

網上有一個栗子,你們能夠參看着本身玩一玩:http://www.javashuo.com/article/p-melniarj-w.html。 對於這個方法,你們本身玩一玩就行了,這裏就不說具體的教程了,畢竟不是本文重點。

QQ羣裏有一個小夥伴大神,他經過 VSTO 來寫的一個框架,其實就是經過命令來將固定的格式進行輸出,這裏盜用一下他的圖,應該還好吧,由於不知道他的博客園帳號,就先不@他了,我的感受這個仍是很不錯的,看着很溜

 這個方法我如今也在學,不過只是作一個知識擴展來用,好處是,咱們本身作一個Excel 工具後,走到哪裏均可以使用,還很方便,本身隨便自定義,不用受項目或者數據庫的環境影響,特別是作展現的時候,很直觀,好比開項目研討會的時候,幾我的討論數據庫表結構呀,生成的方法呀,總不能一個個軟件都打開吧;

可是也有一些問題,畢竟侷限性有些強,好比好像不能直接操做數據庫,在大數據結構中,效率不高,並且不能直接生成文件,須要拷貝操做等;

經過上邊兩個栗子能夠看出來,一個是鏈接數據庫快捷,文件生成方便;一個自定義邏輯性強,展現直觀,那有沒有辦法能夠將兩個優勢結合起來呢,沒錯,就是T4模板了,耐心看完下邊的講解,你會發現很強大。

三、下載該工具

由於有不少小夥伴問到了這個工具,再經得做者贊成之後(做者地址https://github.com/DevilX5,給大神點 Star !),拿到了工具和Code,有須要的小夥伴能夠玩一玩:

工具https://files.cnblogs.com/files/laozhang-is-phi/DxAddIn.rar

Githubhttps://github.com/DevilX5/DxAddIn

 

工具使用很簡單,下載解壓後,就是執行下這個文件,就會在你的Excel中,添加這個服務

你會在你的Excel中發現這個服務:

 

具體的操做,能夠按照上邊做者的動圖來操做。

 

 

3、經過 T4 模板搭建總體項目框架

一、什麼是 T4 模板

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

 

二、在項目中經過T4實現數據庫生成實體類

 這裏就不具體講解 T4 語法了,你們能夠自行學習,其實很簡單,主要仍是 C# 代碼,下邊你看過以後就能懂了,我們首先先實現以前留下的一個伏筆 —— 將咱們的數據庫表利用T4 模板生成實體類,也就是 DbFirst。

一、首先在咱們的項目中,新建一個類庫 Blog.Core.FrameWork 

二、在該類庫下,新建文件夾 Blog.Core.FrameWork.Entity,用於單獨存放咱們的模板以及生成的實體類文件

 

三、在類庫的根目錄新建 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"#>

<#+
//定義管理者 manager 實體類
class Manager
{
    //定義一個 block 塊,主要是應用在批量生產中
    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; }
    //構造函數,包含 host主機,模板,輸出路徑,建立管理策略
    public Manager(ITextTemplatingEngineHost host, StringBuilder template, bool commonHeader) {
        this.host = host;
        this.template = template;
        OutputPath = String.Empty;
        strategy = ManagementStrategy.Create(host);
    }
    //開闢一個 block 塊
    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);
    }
    //定義進程,用來將全部的 blocks 塊執行出來
    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;
            }
        }
    }
}#>

 

四、仍是在類庫根目錄下新建 DbHelper.ttinclude 模板,主要是數據庫操做類

<#+
class DbHelper
    {
        #region 獲取數據庫表結構

        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 獲取表字段信息

        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 獲取 DataTable

        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 獲取主鍵
        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
    }

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; }
    }

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; }
    }

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;
        }
    }
class config
    {
        
        //public static readonly string ConnectionString = "Data Source=.;Initial Catalog=WMBlogDB;User ID=sa;Password=666;";
        public static readonly string ConnectionString = File.ReadAllText(@"D:\my-file\dbCountPsw2.txt").Trim();
        public static readonly string DbDatabase = "";
        public static readonly string TableName = "";
    }#>

 

具體的代碼就不細講了,直接拷貝,或者下載我寫好的代碼便可。再次說明下,本文不會對 T4 語法繼續深刻研究。

 

五、實現生成所有實體類的模型設計,在Blog.Core.FrameWork.Entity文件夾下,新建 Blog.Core.FrameWork.Entity.tt 模板

 

填寫代碼

//若是要獲取主機信息,記得把 hostspecific 設置成true
<#@ template debug="false" hostspecific="True" language="C#" #>
<#@ output extension=".cs" #>

//導入命名空間組件
<#@ assembly name="System.Data" #>
<#@ assembly name="System.xml" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Data.SqlClient" #>
<#@ import namespace="System.Data" #>
<#@ assembly name="System.Core.dll" #>
<#@ assembly name="System.Data.DataSetExtensions.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Xml" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.IO" #>

//引入咱們的公共模板文件
<#@ include file="$(ProjectDir)DbHelper.ttinclude"  #>
<#@ include file="$(ProjectDir)ModelAuto.ttinclude"    #>

//定義咱們的輸出文件夾
<# 
    var OutputPath1 = Path.GetDirectoryName(Host.TemplateFile)+"\\work";
    if (!Directory.Exists(OutputPath1))
    {
        Directory.CreateDirectory(OutputPath1);
    }
     var manager = new Manager(Host, GenerationEnvironment, true) { OutputPath = OutputPath1 }; 
#>


//--------------------------------------------------------------------
//     此代碼由T4模板自動生成
//    老張的哲學 生成時間 <#=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")#> 
//     注意更新後會改變相應代碼。
//--------------------------------------------------------------------
<# 
    var tableName=config.TableName;//獲取config配置中的表名,爲單一輩子產使用
 #>
<# 
if(tableName!=""){//若是表名有值,表示是生成單一文件
    #>  
//引用命名空間
using System;
namespace Blog.Core.FrameWork.Entity
{    
    /// <summary>
    /// <#=tableName#>
    /// </summary>    
    public class <#=tableName#>//能夠在這裏加上基類等
    {
    //將所有字段遍歷出來
<# 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; }
<#}#> 
    }
}
//若是爲空,表示要將整個數據庫都生成出來
<# 
    } else{ 

    #>
    //鏈接數據庫,打開 connect 鏈接
<# 
    SqlConnection conn = new SqlConnection(config.ConnectionString); 
    conn.Open(); 
    System.Data.DataTable schema = conn.GetSchema("TABLES"); 
 #>
 //遍歷所有數據庫表
<# 
    foreach(System.Data.DataRow row in schema.Rows) 
    {  #>   

    //開始啓動block塊,參數是實體類文件名
    <# 
        manager.StartBlock(row["TABLE_NAME"]+".cs");
     #>
    //----------<#=row["TABLE_NAME"].ToString()#>開始----------
    
using System;
namespace Blog.Core.FrameWork.Entity
{    
    /// <summary>
    /// <#=tableName#>
    /// </summary>    
    public class <#=row["TABLE_NAME"].ToString()#>//能夠在這裏加上基類等
    {
    //將該表下的字段都遍歷出來,能夠自定義獲取數據描述等信息
<# foreach(DbColumn column in DbHelper.GetDbColumns(config.ConnectionString, config.DbDatabase, row["TABLE_NAME"].ToString() )){ #>

      public <#= column.CSharpType#> <# if(column.CommonType.IsValueType && column.IsNullable){#> ?<#}#> <#=column.ColumnName #> { get; set; }
<#}#> 

    }
}
    //----------<#=row["TABLE_NAME"].ToString()#>結束----------
    <# 
        manager.EndBlock(); 
        } 
        manager.Process(true);
    }
    #> 

這裏我寫的比較凌亂,大概就是這個邏輯,其實和 C# 特別相像,主要簡單的看一看,就都會明白,這個時候咱們保存文件 ctrl+S,若是你鏈接數據庫正確的話,會發現已經生成了所有實體類文件。

 

隨便打開一個實體類,就能夠發現,和咱們本身寫的是同樣的:是否是很方便!

//----------BlogArticle開始----------
using System;
namespace Blog.Core.FrameWork.Entity
{    
    /// <summary>
    /// BlogArticle
    /// </summary>    
    public class BlogArticle//能夠在這裏加上基類等
    {
    //將該表下的字段都遍歷出來,能夠自定義獲取數據描述等信息
      public int  bID { get; set; }
      public string  bsubmitter { get; set; }
      public string  btitle { get; set; }
      public string  bcategory { get; set; }
      public string  bcontent { get; set; }
      public int  btraffic { get; set; }
      public int  bcommentNum { get; set; }
      public DateTime  bUpdateTime { get; set; }
      public DateTime  bCreateTime { get; set; }
      public string  bRemark { get; set; }
 
    }
}
//----------BlogArticle結束----------
    

 這個時候你會問,這個既然這麼好,能所有生成其餘層麼?沒錯,答案固然是確定的!

 

三、實現整個系統框架模板

 由於篇幅的問題,這裏就不把代碼粘貼出來了,你們本身去Github 上獲取便可,最終的效果是醬紫的:

 

是否是很神奇!整個系統框架就在一瞬間就加載出來了,你們下載好後,只須要 ctrl + S 保存一下 tt 模板文件,就能所有生成,只須要把精力放到 Base 基類/基接口便可,之後數據庫表結構不管如何變化都不怕!

 


 注意:上邊是整個項目都生成出來了,也成功的產生了 work 文件夾下,看似一切很天然,可是不當心就遇到了其餘的問題:

咱們打開 DbHelper.ttinclude 模板的最下邊:

 public static readonly string ConnectionString = File.Exists(@"D:\my-file\dbCountPsw2.txt") ? File.ReadAllText(@"D:\my-file\dbCountPsw2.txt").Trim(): "server=.;uid=sa;pwd=sa;database=WMBlogDB";
 public static readonly string DbDatabase = "";
 public static readonly string TableName = "";//單獨生成一個表

就是上邊,剛剛咱們生成整個庫的時候,這裏是空的,若是如今填寫了一個代表,好比 BlogArticle ,好吧,work 文件夾有了,可是沒有生成指定的 cs 文件類,尷尬,而後就懷疑有 bug,

這個時候請打開 Blog.Core.FrameWork.tt 研究下生成的邏輯代碼,簡單的 if else

 

 

 


 

 

四、Oracle 的T4模板

這裏只有 Model 層的,其餘的自行復制便可。

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

 

生成 model 層 的代碼

感謝小夥伴 @博客園董事長的測試和指正,如下代碼正確,能夠成功導出 Oracle,

<#@ template debug="true" hostspecific="true" language="C#" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Data" #>
<#@ assembly name="System.Data.OracleClient" #>
<#@ assembly name="System.Xml" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Xml" #>
<#@ import namespace="System.Data" #>
<#@ import namespace="System.Data.OracleClient" #>
<#@ import namespace="System.Collections.Generic"#>
<#@ include file="$(ProjectDir)ModelAuto.ttinclude" #>
<# var manager2 = new Manager(Host, GenerationEnvironment, true) { OutputPath = Path.GetDirectoryName(Host.TemplateFile)}; #>
<# 
ModelManager manager = new ModelManager();
List<string> list=manager.GetTableList();
#>

<# 
    foreach (var item in list)
    {
        string tableName=item;
        DataTable table= manager.GetTableSchema(tableName);
 #>

 <# 
        manager2.StartBlock(tableName+".cs");
 #>
using System;
using System.Data;
using System.Data.OracleClient;
namespace Model
{
    /// <summary>
    /// 數據表實體類:<#= tableName #> 
    /// </summary>
    [Serializable()]
    public class <#= tableName #>
    {
<#
foreach(DataRow row in table.Rows)
{
#>
       /// <summary>
       /// <#=row["備註"]#>
       /// </summary>     
       public <#= manager.TransFromSqlType(row["數據類型"].ToString())#> <#=row["字段名"]#>{ get; set; }
<#}
#>
    }
}

<# manager2.EndBlock(); #>

<#
    }  
 #>     
   
<# manager2.Process(true); #>

<#+
    public class ModelManager
    {
        /// <summary>
        /// 數據庫鏈接字符串
        /// </summary>
       private const string CONNECTION_STRING = "Data Source=orcl;Persist Security Info=True;User ID=jjmis;Password=jjmis;Unicode=True";
        /// <summary>
        /// 用戶信息表名
        /// </summary>
        private const string PERSONINFO_TABLE_NAME = "USERINFO";
        /// <summary>
        /// 根據表名查詢表結構信息
        /// </summary>
        private const string SELECT_SCHEMA_BY_TABLE_NAME = @"SELECT A.column_name    字段名,                                                                                           
                                                                    A.data_type      數據類型,
                                                                    A.data_length    長度,
                                                                    A.data_precision 整數位,
                                                                    A.Data_Scale     小數位,
                                                                    A.nullable       容許空值,
                                                                    A.Data_default   缺省值,
                                                                    B.comments       備註,
                                                                    A.TABLE_NAME     表名
                                                                    FROM user_tab_columns A, user_col_comments B
                                                                    WHERE a.COLUMN_NAME = b.column_name
                                                                    AND A.Table_Name = B.Table_Name
                                                                    AND A.Table_Name = '{0}'";

        /// <summary>
        /// 得到數據鏈接
        /// </summary>
        /// <returns></returns>
        private OracleConnection GetConnection()
        {
            return new OracleConnection(CONNECTION_STRING);
        }

        /// <summary>
        /// 獲得當前用戶的全部表名
        /// </summary>
        /// <returns></returns>
        public List<string> GetTableList()
        {
            string sql = "SELECT * FROM USER_TABLES";
            DataTable dt = OracleHelper.ExecuteDataTable(sql);
            List<string> list = new List<string>();
            if (dt!=null&&dt.Rows.Count>0)
            {
                for (int i = 0; i < dt.Rows.Count; i++)
                {
                    list.Add(dt.Rows[i]["TABLE_NAME"].ToString());
                } 
            }
            return list;
         }

        /// <summary>
        /// 釋放鏈接
        /// </summary>
        /// <param name="con"></param>
        private void ReleaseConnection(OracleConnection con)
        {
            if (con != null)
            {
                if (con.State == ConnectionState.Open)
                {
                    con.Close();
                }
            }
        }

        public DataTable GetTableSchema(string tableName)
        {
            DataTable dt;
            using (OracleConnection con = GetConnection())
            {
                con.Open();
                OracleCommand cmd = con.CreateCommand();
                cmd.CommandText = string.Format(SELECT_SCHEMA_BY_TABLE_NAME,tableName);
                cmd.CommandType = CommandType.Text;
                OracleDataAdapter adapter = new OracleDataAdapter(cmd);
                DataSet ds = new DataSet(); 
                adapter.Fill(ds);
                dt = ds.Tables[0];
            }

            return dt;
        }

        /// <summary>
        /// SQL[不完善,須要的本身改造]
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public string TransFromSqlType(string type)
        {
            if (string.IsNullOrEmpty(type))
            {
                return string.Empty;
            }
            if (string.Equals(type, "number", StringComparison.OrdinalIgnoreCase))
            {
                return "int";
            }
            if (string.Equals(type, "date", StringComparison.OrdinalIgnoreCase))
            {
                return "DateTime";
            }
            else if (string.Equals(type, "nvarchar2", StringComparison.OrdinalIgnoreCase))
            {
                return "string";
            }
            return "string";
        }
    }
#>

<#+ 
public class OracleHelper
    {

        private static string oracleConnectionStr = "Data Source=orcl;Persist Security Info=True;User ID=jjmis;Password=jjmis;Unicode=True";
        public static DataTable ExecuteDataTable(string sql, params OracleParameter[] paramList)
        {
            using (OracleConnection conn = new OracleConnection(oracleConnectionStr))
            {
                conn.Open();
                using (OracleCommand command = conn.CreateCommand())
                {
                    command.CommandText = sql;
                    command.Parameters.AddRange(paramList);
                    DataTable dt = new DataTable();
                    OracleDataAdapter adapter = new OracleDataAdapter(command);
                    adapter.Fill(dt);
                    return dt;
                }
            }
        }

        public static int ExecuteNonQuery(string sql, params OracleParameter[] paramList)
        {
            using (OracleConnection conn = new OracleConnection(oracleConnectionStr))
            {
                conn.Open();
                using (OracleCommand command = conn.CreateCommand())
                {
                    command.CommandText = sql;
                    command.Parameters.AddRange(paramList);
                    return command.ExecuteNonQuery();
                }
            }
        }

        public static object ExecuteScalar(string sql, params OracleParameter[] paramList)
        {
            using (OracleConnection conn = new OracleConnection(oracleConnectionStr))
            {
                conn.Open();
                using (OracleCommand command = conn.CreateCommand())
                {
                    command.CommandText = sql;
                    command.Parameters.AddRange(paramList);
                    return command.ExecuteScalar();
                }
            }
        }
    }

 #>
View Code

 

五、Mysql 的T4模板

感謝 @hktkryg 和 @吉喆吉 的意見和建議:

一、若是MySQL要生成大寫的話,須要在my.ini中添加 lower_case_table_names=2,讓mysql區分大小寫,生成出來的就跟所設置的表名,字段名同樣了,默認mysql在windows下不區分大小寫。

二、能夠看看下邊評論區 吉喆吉 博友的意見。

 

對應的 Mysql 的 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"#>

<#+
//定義管理者 manager 實體類
class Manager
{
    //定義一個 block 塊,主要是應用在批量生產中
    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; }
    //構造函數,包含 host主機,模板,輸出路徑,建立管理策略
    public Manager(ITextTemplatingEngineHost host, StringBuilder template, bool commonHeader) {
        this.host = host;
        this.template = template;
        OutputPath = String.Empty;
        strategy = ManagementStrategy.Create(host);
    }
    //開闢一個 block 塊
    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);
    }
    //定義進程,用來將全部的 blocks 塊執行出來
    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;
            }
        }
    }
}#>
ModelAuto.ttinclude

 

對應的 Mysql 的 MySqlHelper.ttinclude 內容:

<#+
public class EntityHelper
    {
        public static List<Entity> GetEntities(string connectionString, List<string> databases)
        {
            var list = new List<Entity>();
            var conn = new MySqlConnection(connectionString);
            try
            {
                conn.Open();
                var dbs = string.Join("','", databases.ToArray());
                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`
                                                FROM `information_schema`.`COLUMNS`
                                                WHERE `information_schema`.`COLUMNS`.`TABLE_SCHEMA` IN ('{0}') ", dbs);
                using (var reader = MySqlHelper.ExecuteReader(conn, cmd))
                {
                    while (reader.Read())
                    {
                        var db = reader["TABLE_SCHEMA"].ToString();
                        var table = reader["TABLE_NAME"].ToString();
                        var column = reader["COLUMN_NAME"].ToString();
                        var type =  reader["DATA_TYPE"].ToString();
                        var comment = reader["COLUMN_COMMENT"].ToString();
                        var entity = list.FirstOrDefault(x => x.EntityName == table);
                        if(entity == null)
                        {
                            entity = new Entity(table);
                            entity.Fields.Add(new Field
                            {
                                Name = column,
                                Type = GetCLRType(type),
                                Comment = comment
                            });
                           
                            list.Add(entity);
                        }
                        else
                        {
                            entity.Fields.Add(new Field
                            {
                                Name = column,
                                Type = GetCLRType(type),
                                Comment = comment
                            });
                        }
                    }
                }
            }
            finally
            {
                conn.Close();
            }

            return list;
        }

        public static string GetCLRType(string dbType)
        {
            switch(dbType)
            {
                case "tinyint":
                case "smallint":
                case "mediumint":
                case "int":
                case "integer":
                    return "int";
                case "double":
                    return "double";
                case "float":
                    return "float";
                case "decimal":
                    return "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:
                    return dbType;
            }
        }
    }

    public class Entity
    {
        public Entity()
        {
            this.Fields = new List<Field>();
        }

        public Entity(string name)
            : this()
        {
            this.EntityName = name;
        }

        public string EntityName { get;set; }
        public List<Field> Fields { get;set; }
    }

    public class Field
    {
        public string Name { get;set; }
        public string Type { get;set; }
        public string Comment { get;set; }
    }

class config
    {
        
        public static readonly string ConnectionString = "Database=appsoft;Data Source=127.0.0.1;User Id=root;Password=123456;pooling=false;CharSet=utf8;port=3306";
        public static readonly string DbDatabase = "";
        public static readonly string TableName = "";
        public static readonly string ModelNameSpace = "App.Entities";
        public static readonly string IRepositoryNameSpace = "App.IRepository";
        public static readonly string RepositoryNameSpace = "App.Repository";
        public static readonly string IServicesNameSpace = "App.IServices";
        public static readonly string ServicesNameSpace = "App.Services";
    }#>
MySqlHelper.ttinclude

具體的Demo項目詳情,能夠下載:https://files.cnblogs.com/files/laozhang-is-phi/App.T4.MySql.rar

 

 注意事項:
一、<#@ assembly name="C:\Users\youga\.nuget\packages\mysql.data\8.0.14\lib\net452\MySql.Data.dll" #>  修改成你的引用;
二、MySqlHelper.ttinclude 修改ConnectionString變量;
三、 App.Entities.tt 修改connectionString變量;
四、能夠根據本身的需求修改T4模板;
五、生成的類名都是小寫,能否轉化爲帕斯卡命名規範(待解決); 

 

 

4、SqlSugar等ORM框架來實現 DbFirst

 通常的ORM都會有這個功能,不管是Code First ,仍是根據數據庫DB來生成 .cs 實體類,個人項目用的是Sqlsugar,因此也封裝了響應的方法,

具體代碼,能夠參考 blog.core層下的 Controllers / DbFirst / DbFirstController.cs 文件,裏邊有對Repository、IRepository、Service、IService、Model層的自動生成接口,

代碼很簡單,看看就好了。

 

 

 

 

 

5、結語

 今天也是在忙碌中,抽出時間寫了寫,主要是給你們分享了下,如何快速的半自動化的實現項目搭建,也算是一個小技巧了,重點說明了下 T4模板搭建所有層文件,我的感受仍是可行的,主要是靈活性很強,須要的小夥伴能夠好好的研究一下,繼續奮鬥中!!!

 

感謝羣內大神提供開源資料:

經過Visual Studio擴展開發實現領域驅動開發

VisualStudio 擴展開發

Resharper 自定義代碼片

 

6、Github代碼

https://github.com/anjoy8/Blog.Core

相關文章
相關標籤/搜索