1. 程式人生 > >從壹開始前後端分離 [.netCore 填坑 ] 三十二║ 四種方法快速實現專案的半自動化搭建

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

更新

1、更新小夥伴 @ 提出好點子:試試VS的外掛擴充套件:VSIX、ItemProject等,將T4模板給製作外掛,這裡先記下,有懂的小夥伴可以自己先試試,我會在以後更新。

2、感謝小夥伴  @的測試和指正,本文 T4 模板已經支援 Oracle

緣起

哈嘍大家週二好呀,這個國慶過的真是懶洋洋呀,不知道大家的學習動力咋樣了,剛一上班本人手中的專案也增加了,但是還是要抽出時間學習噠,為了不讓老闆大大天天催,所以更新會慢點兒 [ 哭笑 ] :bowtie:,不過在我的推薦下,公司下一個專案要我負責前後端分離,終於可以將這些派上用場了,中間的坑也會在以後的文章中,慢慢補充出來。

這幾天簡單想了想,還沒有想好要開什麼系列,就想到QQ群裡有小夥伴問的較多的一些問題以及前邊系列文章中的提到的,但是沒有深入講到的,再填一下坑,這樣才是完整的嘛,大家要是看到之前的有任何不清楚的,或者想擴充套件的,可以在群裡說一下,或者留言,我都會說到的。今天呢,就說說如果半自動化搭建專案,這個坑來自於之前的專案搭建文章《框架之六 || API專案整體搭建 6.1 倉儲模式》的伏筆之一 —— 如何使用 T4 模板搭建專案。當然,我們不僅是簡單說說實體類的建立,也會橫向和縱向的討論下,一個專案如何通過程式碼實現半自動化搭建。

說到這裡大家應該已經明白了這篇文章的寫作意圖,就是搭建專案的問題,相信大家已經開發了幾年了,都有自己的一套行之有效的辦法或者是經驗,當然這裡就不說付費的了,付費的框架何其多,比如迪西客,普元或者力軟等等,這都是好用的功能強大的付費框架,既然說技術,就不說付費的,咱們自己寫,這裡簡單概括下今天要說到的:

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

1、動軟程式碼生成器 —— 這個我入門的時候使用的神器,用了好久

2、通過 VSTO 來編寫 Excel ,實現每一層的程式碼設計 —— 我沒用過,但是見過,一個不錯的思路

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

4、SqlSuagr(ORM)—— 自封裝的一套邏輯,當然其他ORM也有,比如EF就很好

5、VSIX 擴充套件外掛 —— 新的處理方案

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

框架截圖

一、動軟程式碼生成器搭建整體專案框架

相信很多的小夥伴應該使用過這個工具,還是很不錯的,我也是用了有一段時間,雖然很小,但是功能確實很豐富,無論是生成實體類,還是生成簡單三層,還是工廠模式等等,都可以使用,不僅支援單個表文件的操作,也支援整個資料庫的批量生成,這裡具體的不做敘述,因為不是本篇文章的重點,這裡簡單的說下使用方法以及效果圖:

1、安裝與使用

安裝還是很簡單的,就是普通的 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 [email protected]");
            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("[email protected],");
            strSql.Append("[email protected],");
            strSql.Append("[email protected],");
            strSql.Append("[email protected],");
            strSql.Append("[email protected],");
            strSql.Append("[email protected],");
            strSql.Append("[email protected],");
            strSql.Append("[email protected],");
            strSql.Append("[email protected]");
            strSql.Append(" where [email protected]");
            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 [email protected]");
            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 [email protected]");
            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 搭建多層框架,動軟程式碼生成器是一個不錯的選擇。

二、通過 VSTO 編寫 Excel 來搭建整體專案框架

1、什麼是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

2、如何新建一個 VSTO 專案

QQ群裡有一個小夥伴大神,他通過 VSTO 來寫的一個框架,其實就是通過命令來將固定的格式進行輸出,這裡盜用一下他的圖,應該還好吧,因為不知道他的部落格園賬號,就先不@他了,個人感覺這個還是很不錯的,看著很溜

 這個方法我現在也在學,不過只是做一個知識擴充套件來用,好處是,我們自己做一個Excel 工具後,走到哪裡都可以使用,還很方便,自己隨便自定義,不用受專案或者資料庫的環境影響,特別是做展示的時候,很直觀,比如開專案研討會的時候,幾個人討論資料庫表結構呀,生成的方法呀,總不能一個個軟體都開啟吧;

但是也有一些問題,畢竟侷限性有些強,比如好像不能直接操作資料庫,在大資料結構中,效率不高,而且不能直接生成檔案,需要拷貝操作等;

通過上邊兩個栗子可以看出來,一個是連線資料庫快捷,檔案生成方便;一個自定義邏輯性強,展示直觀,那有沒有辦法可以將兩個優點結合起來呢,沒錯,就是T4模板了,耐心看完下邊的講解,你會發現很強大。

三、通過 T4 模板搭建整體專案框架

1、什麼是 T4 模板

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

2、在專案中通過T4實現資料庫生成實體類

 這裡就不具體講解 T4 語法了,大家可以自行學習,其實很簡單,主要還是 C# 程式碼,下邊你看過之後就能懂了,咱們首先先實現之前留下的一個伏筆 —— 將我們的資料庫表利用T4 模板生成實體類,也就是 DbFirst。

1、首先在我們的專案中,新建一個類庫 Blog.Core.FrameWork 

2、在該類庫下,新建資料夾 Blog.Core.FrameWork.Entity,用於單獨存放我們的模板以及生成的實體類檔案

3、在類庫的根目錄新建 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) {
        IServiceProvid