月份: 2020 年 9 月

  • FreeSql.Generator命令行代碼生成器是如何實現的

    FreeSql.Generator命令行代碼生成器是如何實現的

    目錄

    • FreeSql介紹
    • FreeSql.Generator
    • RazorEngine.NetCore
    • 源碼解析
    • FreeSql.Tools

    FreeSql

    FreeSql 是功能強大的對象關係映射技術(O/RM),支持 .NETCore 2.1+ 或 .NETFramework 4.0+ 或 Xamarin。

    有一個強大的ORM,也方便我們開發一個代碼生成器。

    一般情況下,我們開發數據庫相關的應用,主要分為三種code first、db first、model first

    我只用過前二種,

    • code first,代碼優先,數據庫都是根據實體類生成,所有的關係,可以是邏輯關聯,也可以是物理關聯。
    • DB First: 數據庫優先,直接設計表結構,用設計工具生成表,設計主鍵,外鍵、索引,關聯關係等。

    當我們使用DB First時,設計好的數據庫,我們怎麼生成一些實體類、通用的代碼、控制器、服務層、Dto呢。今天我來給大家介紹一下FreeSql項目中的一些工具。當然,不使用此ORM的小夥伴也能使用此工具,因為他是通用。

    FreeSql.Generator 命令行方式

    通過幾行命令,就可實現生成項目中通用的代碼結構,不需要複製一段代碼后修改,加快開發速度,減少重複勞動,少用一根頭髮。

    由於每個人的項目結構,代碼位置各不相同,對於ORM來說,不同的業務邏輯各不相同,所以該項目沒有相應的模板,相信使用過Razor的同學一定能實現自己的模板。

    1-2年前,我和一個學長也寫過代碼生成器,這裏分享一下當時做項目時的一些模板,https://github.com/i542873057/SJNScaffolding/tree/master/SJNScaffolding.RazorPage/Templates,該項目是基於 . NET Core+Razor Page,由於已離職,所以沒有繼續維護,這些模板都和ABP相關,當時提取了一些通用的功能,單表操作,可以直接生成前後端功能,只需要在word中按統一的格式寫好數據字典的文檔,直接複製到系統,即可根據空格,定義類型等方式解析字段。

    回到FreeSql.Generator 命令行

    • 對於此工具的使用可參考 https://github.com/dotnetcore/FreeSql/wiki/DbFirst
    • 源碼位置 https://github.com/dotnetcore/FreeSql/tree/master/Extensions/FreeSql.Generator
    • 前提是本地安裝了.net core 3.1 的sdk.

    怎麼使用呢。

    1. 安裝 dotnet-tool 生成實體類
    dotnet tool install -g FreeSql.Generator
    
    1. 新建目錄,在地址欄輸入 cmd 快速打開命令窗口,輸入命令:
    FreeSql.Generator --help
    

    我們可以看到

    C:\Users\igeekfan\Desktop\code>FreeSql.Generator --help
            ____                   ____         __
           / __/  ____ ___  ___   / __/ ___ _  / /
          / _/   / __// -_)/ -_) _\ \  / _ `/ / /
         /_/    /_/   \__/ \__/ /___/  \_, / /_/
                                        /_/
    
    
      # Github # https://github.com/2881099/FreeSql v1.5.0
    
        使用 FreeSql 快速生成數據庫的實體類
    
        更新工具:dotnet tool update -g FreeSql.Generator
    
    
      # 快速開始 #
    
      > FreeSql.Generator -Razor 1 -NameOptions 0,0,0,0 -NameSpace MyProject -DB "MySql,Data Source=127.0.0.1;..."
    
         -Razor 1                  * 選擇模板:實體類+特性
    
         -Razor 2                  * 選擇模板:實體類+特性+導航屬性
    
         -Razor "d:\diy.cshtml"    * 自定義模板文件
    
         -NameOptions              * 總共4個布爾值,分別對應:
                                   # 首字母大寫
                                   # 首字母大寫,其他小寫
                                   # 全部小寫
                                   # 下劃線轉駝峰
    
         -NameSpace                * 命名空間
    
         -DB "MySql,Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=數據庫;Charset=utf8;SslMode=none;Max pool size=2"
    
         -DB "SqlServer,Data Source=.;Integrated Security=True;Initial Catalog=數據庫;Pooling=true;Max Pool Size=2"
    
         -DB "PostgreSQL,Host=192.168.164.10;Port=5432;Username=postgres;Password=123456;Database=數據庫;Pooling=true;Maximum Pool Size=2"
    
         -DB "Oracle,user id=user1;password=123456;data source=//127.0.0.1:1521/XE;Pooling=true;Max Pool Size=2"
    
         -DB "Sqlite,Data Source=document.db"
    
         -DB "Dameng,server=127.0.0.1;port=5236;user id=2user;password=123456789;database=2user;poolsize=2"
                                   Dameng 是國產達夢數據庫
    
         -Filter                   Table+View+StoreProcedure
                                   默認生成:表+視圖+存儲過程
                                   如果不想生成視圖和存儲過程 -Filter View+StoreProcedure
    
         -Match                    正則表達式,只生成匹配的表,如:dbo\.TB_.+
    
         -FileName                 文件名,默認:{name}.cs
    
         -Output                   保存路徑,默認為當前 shell 所在目錄
                                   推薦在實體類目錄創建 gen.bat,雙擊它重新所有實體類
    
    • 更新命令行
    dotnet tool update -g FreeSql.Generator
    
    1. 這裏lin-cms-dotnetcore這個項目來測試。

    • 數據庫表名是下劃線,字段也是下劃線方式。
    • -Razor 指定 第一個模板
    • -NameOptions 0,0,0,1 最後一個1,代表 下劃線轉駝峰,滿足C#命名規則
    • -NameSpace 指定了命名空間 LinCms.Core.Entities
    • -DB 就是數據庫的相關配置
    • mysql 本地地址 127.0.0.1 3306端口 用戶名 root 密碼123456 數據庫 lin-cms
    • -Match book 這樣就能只生成book,支持正則表達式,如 -Math lin_user 就會生成以lin_user開頭的表。如dbo.TB_.+,會生成以TB開頭的表。即只生成匹配的表
    1. 執行此命令。
    FreeSql.Generator -Razor 1  -NameOptions 0,0,0,1 -NameSpace LinCms.Core.Entities -DB "MySql,Data Source=127.0.0.1;Port=3306;User ID=root;Password=123456;Initial Catalog=lincms;Charset=utf8;SslMode=none;Max pool size=2"
    

    這時候代碼已經生成了

    其中一個代碼 生成如下。這些類是partial ,熟悉C#的同學,應該知道,類的定義使用此關鍵字,我們能在不同的地方為該類擴展。以防止重新同步數據庫的結構時,丟失改動的字段。

    namespace LinCms.Core.Entities {
    
    	[JsonObject(MemberSerialization.OptIn), Table(Name = "book")]
    	public partial class Book {
    
    		/// <summary>
    		/// 主鍵Id
    		/// </summary>
    		[JsonProperty, Column(Name = "id", IsPrimary = true, IsIdentity = true)]
    		public long Id { get; set; }
    
    		[JsonProperty, Column(Name = "author", DbType = "varchar(20)")]
    		public string Author { get; set; } = string.Empty;
    
    		[JsonProperty, Column(Name = "image", DbType = "varchar(50)")]
    		public string Image { get; set; } = string.Empty;
    
            //更多xxx
    	}
    
    }
    
    
    • 最終效果圖如下

    此時會生成二個文件
    __重新生成.bat,下次重新點擊他就能重新生成實體類了。

    FreeSql.Generator -Razor "__razor.cshtml.txt" -NameOptions 1,1,0,1 -NameSpace MyProject -DB "MySql,Data Source=127.0.0.1;Port=3306;User ID=root;Password=123456;Initial Catalog=lincms;Charset=utf8;SslMode=none;Max pool size=2" -FileName "{name}.cs"
    

    上面的命令-Razor 指定了這個txt文件 __razor.cshtml.txt

    我們可以定義自己的模板,以生成符合自已業務的的代碼,從而實現快速開發。

    我們可以看下模板中的文件內容,他就是asp.net下的mvc 結構下的razor後端模板渲染,把這個.txt後綴去掉,就很明了了。對於asp.net mvc的razor,我們可以將控制器下方法的值替換掉cshtml中的值。這個過程是有一個類庫在幫我們實現的,叫RazorEngine,不過那個是.net framework下的實踐。.NET Framework 下的RazorEngine代碼生成介紹

    @using FreeSql.DatabaseModel;@{
    var gen = Model as RazorModel;
    
    Func<string, string> GetAttributeString = attr => {
    	if (string.IsNullOrEmpty(attr)) return null;
    	return string.Concat(", ", attr.Trim('[', ']'));
    };
    Func<DbColumnInfo, string> GetDefaultValue = col => {
        if (col.CsType == typeof(string)) return " = string.Empty;";
        return "";
    };
    }
    //xxx
    namespace @gen.NameSpace {
    
    @if (string.IsNullOrEmpty(gen.table.Comment) == false) {
    	@:/// <summary>
    	@:/// @gen.table.Comment.Replace("\r\n", "\n").Replace("\n", "\r\n		/// ")
    	@:/// </summary>
    }
    	[JsonObject(MemberSerialization.OptIn)@GetAttributeString(gen.GetTableAttribute())]
    	public partial class @gen.GetCsName(gen.FullTableName) {
    
    	@foreach (var col in gen.columns) {
    
    		if (string.IsNullOrEmpty(col.Coment) == false) {
    		@:/// <summary>
    		@:/// @col.Coment.Replace("\r\n", "\n").Replace("\n", "\r\n		/// ")
    		@:/// </summary>
    		}
    		@:@("[JsonProperty" + GetAttributeString(gen.GetColumnAttribute(col)) + "]")
    		@:public @gen.GetCsType(col) @gen.GetCsName(col.Name) { get; set; }@GetDefaultValue(col)
    @:
    	}
    	}
    @gen.GetMySqlEnumSetDefine()
    }
    

    RazorEngine.NetCore

    到了.NET Core時代,我看了下FreeSql.Generator用的這個類庫RazorEngine.NetCore,實現動態操作cshtml,生成需要的文本。

    Razor Engine是基於微軟Razor解析的模板引擎,它允許你使用Razor語法構建動態模板,你只需要使用Engine的靜態方法,Engine.Razor.RunCompile等。

    創建一個控制台應用,然後安裝包。

    Install-Package RazorEngine.NetCore
    
    using RazorEngine;
    using RazorEngine.Templating; // For extension methods.
    
    
    string template = "Hello @Model.Name, welcome to RazorEngine!";
    var result = Engine.Razor.RunCompile(template, "templateKey", null, new { Name = "World" });
    
    Console.WriteLine(result);
    
    • 輸出如下內容
    Hello World, welcome to RazorEngine!
    

    此處使用的RunCompile方法是擴展方法,您需要引用RazorEngine.Templating命名空間。

    The “templateKey” 保持唯一值,比如使用guid值。字符串,並且你可以根據此字符串key重新運行緩存的模板。

    如果再次根據此key,可使用原本的模板。

    var result = Engine.Razor.Run("templateKey", null, new { Name = "Max" });
    
    • 會輸出如下內容
    Hello Max, welcome to RazorEngine!
    

    上面中的RunCompile第三個參數,傳null,因為我們第四個參數使用的是匿名類,

    根目錄創建一個HelloWord.cshtml,要選擇屬性,->如果較新則複製 內容,

    Hello @Model.Name, welcome to RazorEngine!
    

    控制台如下代碼。

    string templateFilePath = "HelloWorld.cshtml";
    var templateFile = File.ReadAllText(templateFilePath);
    string templateFileResult = Engine.Razor.RunCompile(templateFile, Guid.NewGuid().ToString(), null, new
    {
        Name = "World"
    });
    
    Console.WriteLine(templateFileResult);
    
    • 控制台輸出
    Hello World, welcome to RazorEngine!
    
    • 使用強類型 CopyRightUserInfo.cs生成一個版權所有
    using System;
    namespace OvOv.Razor
    {
        public class CopyRightUserInfo
        {
            public string UserName { get; set; }
            public string EmailAddress { get; set; }
            public DateTime CreateTime { get; set; }
            public string FileRemark { get; set; }
        }
    
    }
    

    根目錄創建一個CopyRightTemplate.cshtml,要選擇屬性,->如果較新則複製 內容,

    @{
        var gen = Model as OvOv.Razor.CopyRightUserInfo;
    }
    //=============================================================
    // 創建人:            @gen.UserName
    // 創建時間:          @gen.CreateTime
    // 郵箱:             @gen.EmailAddress
    //==============================================================
    
    

    控制台如下代碼。

    string copyRightTemplatePath = "CopyRightTemplate.cshtml";
    var copyRightTemplate = File.ReadAllText(copyRightTemplatePath);
    string copyRightResult = Engine.Razor.RunCompile(copyRightTemplate, Guid.NewGuid().ToString(), typeof(CopyRightUserInfo), new CopyRightUserInfo
    {
        CreateTime = DateTime.Now,
        EmailAddress = "710277267@qq.com",
        UserName = "IGeekFan"
    });
    Console.WriteLine(copyRightResult);
    
    Console.ReadKey();
    
    • 控制台輸出
    //=============================================================
    // 創建人:            IGeekFan
    // 創建時間:          2020/6/23 18:14:08
    // 郵箱:             710277267@qq.com
    //==============================================================
    

    全放到控制台下,輸出如下結果。代碼生成器最重要的一點解決了,我們就能實現自己的代碼生成器,先構建自己的模板,實現輸入(命令行,WPF,WEB端及更多),輸出(生成文件)。

    • 以上源碼已放到示例代碼中 https://github.com/luoyunchong/dotnetcore-examples/blob/master/aspnetcore-freesql/OvOv.Razor/Program.cs

    源碼解析

    首先這是一個控制台應用,Main(string[] args)可接收多個參數。

    1. 處理無參數,–help
    2. 處理args數組,解析出所有的參數,如果沒有設置,則為默認值。(處理一些參數異常問題)最重要的是根據-Razor,選定對應的模板。
    ArgsRazor=""//根據-Razor  1 不是2 還是模板的路徑,取出的模板文本值。
    var razorId = Guid.NewGuid().ToString("N");
    RazorEngine.Engine.Razor.Compile(ArgsRazor, razorId);
    
    1. 根據數據庫連接串,取出參數過濾后的表,視圖,存儲過程
    2. 循環數據庫的表等,
    • model為模板中需要的數據
    • razorId與上文的razorId相同,
    • sw為生成后的文本保存的值。
    var sw = new StringWriter();
    var model = new RazorModel(fsql, ArgsNameSpace, ArgsNameOptions, tables, table);
    RazorEngine.Engine.Razor.Run(razorId, sw, null, model);
    
    1. 將sw字符串保存生成類.cs文件(根據參數配置生成文件名)
    2. 另外生成一個__重新生成.bat,__razor.cshtml.txt,方便後續用戶重新生成實體類。

    FreeSql.Tools

    這是 FreeSql 衍生出來的輔助工具包,內含生成器等功能;作者:mypeng1985
    因為這個不兼容mac,linux,所以作者建議使用dotnet-tool 命令行工具生成實體類,從而支持MAC/Linux系統。對於不是使用FreeSql的開發者,也能使用此工具,你只需要修改對應的模板即可。

    使用方式:不多介紹。

    • https://github.com/2881099/Freesql.tools
    • 分為WPF ,WinForm + DSkin 版本(套網頁)
    • 看了下代碼,底層生成代碼邏輯也是用的RazorEngine .NET Framework 下的RazorEngine代碼生成介紹

    FreeSql官方群 4336577

    預覽圖

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※超省錢租車方案

    ※別再煩惱如何寫文案,掌握八大原則!

    ※回頭車貨運收費標準

    ※教你寫出一流的銷售文案?