基於SqlSugar的開發框架循序漸進介紹(3)-- 實現代碼生成工具Database2Sharp的整合開發

来源:https://www.cnblogs.com/wuhuacong/archive/2022/05/16/16270542.html
-Advertisement-
Play Games

我喜歡在一個項目開發模式成熟的時候,使用代碼生成工具Database2Sharp來配套相關的代碼生成,對於我介紹的基於SqlSugar的開發框架,從整體架構確定下來後,我就著手為它們量身定做相關的代碼開發,這樣可以在後續整合項目功能的時候,利用代碼生成工具快速的生成所需要模塊的骨架代碼,然後在這個基... ...


我喜歡在一個項目開發模式成熟的時候,使用代碼生成工具Database2Sharp來配套相關的代碼生成,對於我介紹的基於SqlSugar的開發框架,從整體架構確定下來後,我就著手為它們量身定做相關的代碼開發,這樣可以在後續整合項目功能的時候,利用代碼生成工具快速的生成所需要模塊的骨架代碼,然後在這個基礎上逐漸增加自定義的內容即可,方便快捷。本篇隨筆介紹基於SqlSugar的開發框架,對框架中涉及到的各個分層或者模塊代碼進行生成的處理。

1、回顧項目的架構和模塊內容

在前面幾篇隨筆中,大概介紹過了基於SqlSugar的開發框架主要的設計模塊,場景如下所示。

基礎核心數據模塊SugarProjectCore,主要就是開發業務所需的數據處理和業務邏輯的項目,為了方便,我們區分Interface、Modal、Service三個目錄來放置不同的內容,其中Modal是SqlSugar的映射實體,Interface是定義訪問介面,Service是提供具體的數據操作實現。其中Service裡面一些框架基類和介面定義,統一也放在公用類庫裡面。

Winform界面,我們可以採用基於.net Framework開發或者.net core6進行開發均可,因為我們的SugarProjectCore項目是採用.net Standard模式開發,相容兩者。

這裡以許可權模塊來進行演示整合使用,我在構建代碼生成工具代碼模板的時候,反覆利用項目中測試沒問題的項目代碼指導具體的模板編寫,這樣編寫出來的模板就會完美符合實際的項目需要了。

在項目代碼及模板完成後,利用代碼生成工具快速生成代碼,相互促進情況下,也完成了Winform項目的界面代碼生成,生成包括普通的列表界面,以及主從表Winform界面代碼生成。

最後許可權系統的Winform項目如下所示。

在前面隨筆《基於SqlSugar的開發框架循序漸進介紹(2)-- 基於中間表的查詢處理》中介紹了基礎功能的一些處理,其中也介紹到了Winform界面端的界面效果,這個以SqlSugar底層處理,最終把許可權、字典等模塊整合到一起,完成一個項目開發所需要的框架結構內容。整個系統包括用戶管理、組織機構管理、角色管理、功能許可權管理、菜單管理、欄位許可權管理、黑白名單、操作日誌、字典管理、客戶信息等模塊內容。

在代碼生成工具中,我們整合了基於SqlSugar的開發框架的項目代碼生成,包括框架基礎的代碼生成,以及Winform界面代碼生成兩個部分,框架項目及Winform界面效果如上圖所示。

 

2、整合代碼生成工具Database2Sharp進行SqlSugar框架代碼生成

前面隨筆介紹過基於SqlSugar核心Core項目的組成。

基礎核心數據模塊SugarProjectCore,主要就是開發業務所需的數據處理和業務邏輯的項目,為了方便,我們區分Interface、Modal、Service三個目錄來放置不同的內容,其中Modal是SqlSugar的映射實體,Interface是定義訪問介面,Service是提供具體的數據操作實現。

對於Modal層的類代碼生成,常規的普通表(非中間表),我們根據項目所需要,生成如下代碼。目的是利用它定義好對應的主鍵Id,並通過介面約束實體類。

    /// <summary>
    /// 客戶信息
    /// 繼承自Entity,擁有Id主鍵屬性
    /// </summary>
    [SugarTable("T_Customer")]
    public class CustomerInfo : Entity<string>

而對於中間表,我們不要它的繼承繼承關係。

    /// <summary>
    /// 用戶角色關聯
    /// </summary>
    [SugarTable("T_ACL_User_Role")]
    public class User_RoleInfo
    {
    }

只需要簡單的標註好SugarTable屬性,讓他可以和其他業務表進行關聯查詢即可。

        /// <summary>
        /// 根據用戶ID獲取對應的角色列表
        /// </summary>
        /// <param name="userID">用戶ID</param>
        /// <returns></returns>
        private async Task<List<RoleInfo>> GetByUser(int userID)
        {
            var query = this.Client.Queryable<RoleInfo, User_RoleInfo>(
            (t, m) => t.Id == m.Role_ID && m.User_ID == userID)
            .Select(t => t); //聯合條件獲取對象

            query = query.OrderBy(t => t.CreateTime);//排序
            var list = await query.ToListAsync();//獲取列表
            return list;
        }

對於介面層的類,我們只需要按固定的繼承關係處理好,以及類的名稱變化即可。

    /// <summary>
    /// 系統用戶信息,應用層服務介面定義
    /// </summary>
    public interface IUserService : IMyCrudService<UserInfo, int, UserPagedDto>, ITransientDependency
    {
    }

其中 IMyCrudService 是我們定義的基類介面,保存常規的增刪改查等的處理基類,通過傳入泛型進行約束介面參數類型和返回值。

基類介面儘可能滿足實際項目介面所需,這樣可以減少子類的代碼編寫,以及獲得統一調用基類函數的便利。

 

對於中間表,我們除了生成實體類外,不需要生成其他介面和介面實現層,因為我們不單獨調用它們。

對於具體業務對象對應的介面實現,我們除了確定它的繼承關係外,我們還會重寫它們的一些基類函數,從而實現更加精準的處理。

 介面實現類的定義如下所示。

    /// <summary>
    /// 應用層服務介面實現
    /// </summary>
    public class CustomerService : MyCrudService<CustomerInfo, string, CustomerPagedDto>, ICustomerService
    {

    }

一般情況下,我們至少需要在子類重寫 CreateFilteredQueryAsync 和 ApplyDefaultSorting 兩個函數,前者是條件的查詢處理,後者是預設的排序處理操作。

        /// <summary>
        /// 自定義條件處理
        /// </summary>
        /// <param name="input">查詢條件Dto</param>
        /// <returns></returns>
        protected override ISugarQueryable<CustomerInfo> CreateFilteredQueryAsync(CustomerPagedDto input)
        {
            var query = base.CreateFilteredQueryAsync(input);

            query = query
                .WhereIF(!input.ExcludeId.IsNullOrWhiteSpace(), t => t.Id != input.ExcludeId) //不包含排除ID
                .WhereIF(!input.Name.IsNullOrWhiteSpace(), t => t.Name.Contains(input.Name)) //如需要精確匹配則用Equals
                                                                                             //年齡區間查詢
                .WhereIF(input.AgeStart.HasValue, s => s.Age >= input.AgeStart.Value)
                .WhereIF(input.AgeEnd.HasValue, s => s.Age <= input.AgeEnd.Value)

                //創建日期區間查詢
                .WhereIF(input.CreateTimeStart.HasValue, s => s.CreateTime >= input.CreateTimeStart.Value)
                .WhereIF(input.CreateTimeEnd.HasValue, s => s.CreateTime <= input.CreateTimeEnd.Value)
                ;

            return query;
        }

        /// <summary>
        /// 自定義排序處理
        /// </summary>
        /// <param name="query">可查詢LINQ</param>
        /// <returns></returns>
        protected override ISugarQueryable<CustomerInfo> ApplyDefaultSorting(ISugarQueryable<CustomerInfo> query)
        {
            return query.OrderBy(t => t.CreateTime, OrderByType.Desc);

            //如果先按第一個欄位排序,然後再按第二欄位排序,示例代碼
            //return base.ApplySorting(query, input).OrderBy(s=>s.Customer_ID).OrderBy(s => s.Seq);
        }

根據這些規則,編寫我們所需的模板代碼,讓我們選擇的資料庫表名稱、註釋,以及表欄位的名稱、類型、註釋,外鍵主鍵關係等信息為我們模板所用。

如下所示代碼是NVelocity模板代碼,用於生成上面的條件查詢處理的,可以稍作瞭解。

        /// <summary>
        /// 自定義條件處理
        /// </summary>
        /// <param name="input">查詢條件Dto</param>
        /// <returns></returns>
        protected override ISugarQueryable<${ClassName}Info> CreateFilteredQueryAsync(${ClassName}PagedDto input)
        {
            var query = base.CreateFilteredQueryAsync(input);
             query = query
#if(${PrimaryKeyNetType}=="string")
                .WhereIF(!input.ExcludeId.IsNullOrWhiteSpace(), t=>t.Id != input.ExcludeId) //不包含排除ID
#else
                .WhereIF(input.ExcludeId.HasValue, t=>t.Id != input.ExcludeId) //不包含排除ID
#end
#foreach($EntityProperty in $EntityPropertyList) 
#if(${EntityProperty.ColumnInfo.IsForeignKey} || ${EntityProperty.PropertyName}  == "Status" || ${EntityProperty.PropertyName}  == "State" || ${EntityProperty.PropertyName}  == "PID" || ${EntityProperty.PropertyName}  == "Deleted")
                .WhereIF(#if(${EntityProperty.ColumnInfo.IsNumeric})input.${EntityProperty.PropertyName}.HasValue#else!input.${EntityProperty.PropertyName}.IsNullOrWhiteSpace()#end, s => s.${EntityProperty.PropertyName} == input.${EntityProperty.PropertyName})
#elseif(${EntityProperty.ColumnInfo.IsDateTime} || ${EntityProperty.ColumnInfo.IsNumeric})
                //${EntityProperty.Description}區間查詢
                .WhereIF(input.${EntityProperty.PropertyName}Start.HasValue, s => s.${EntityProperty.PropertyName} >= input.${EntityProperty.PropertyName}Start.Value)
                .WhereIF(input.${EntityProperty.PropertyName}End.HasValue, s => s.${EntityProperty.PropertyName} <= input.${EntityProperty.PropertyName}End.Value)
#elseif(${EntityProperty.ColumnInfo.NetType.Alias.ToLower()} != "byte[]" && ${EntityProperty.ColumnInfo.Name.Name.ToString()} != "AttachGUID")
                .WhereIF(#if(${EntityProperty.NetType.EndsWith("?")})input.${EntityProperty.PropertyName}.HasValue, t => t.${EntityProperty.PropertyName} == input.${EntityProperty.PropertyName}#else!input.${EntityProperty.PropertyName}.IsNullOrWhiteSpace(), t => t.${EntityProperty.PropertyName}.Contains(input.${EntityProperty.PropertyName})#end) //如需要精確匹配則用Equals
#end ##endif
#end

#if(${HasCreationTime}) 
                //創建日期區間查詢
                .WhereIF(input.CreationTimeStart.HasValue, s => s.CreationTime >= input.CreationTimeStart.Value)
                .WhereIF(input.CreationTimeEnd.HasValue, s => s.CreationTime <= input.CreationTimeEnd.Value)
#else
                //創建日期區間查詢(參考)
                //.WhereIF(input.CreationTimeStart.HasValue, s => s.CreationTime >= input.CreationTimeStart.Value)
                //.WhereIF(input.CreationTimeEnd.HasValue, s => s.CreationTime <= input.CreationTimeEnd.Value)
#end;
            return query;
        }

 

當我們完成所需的模板代碼開發後,就在代碼生成工具主體界面中整合相關的生成功能菜單,界面效果如下所示。

 通過菜單選擇【SqlSugar框架代碼生成】,進一步選擇資料庫中的表進行生成,一步步處理即可,最後列出所選資料庫表,並確認生成操作,即可生成SqlSugar框架核心項目的代碼,如下圖所示。

選擇表進行生成後,生成的實體模型類如下所示,包括生成了中間表的實體類。

 

 而介面實現則是根據具體的業務對象規則進行生成。

 

 

3、SqlSugar項目中Winform界面的生成 

Winform界麵包括普通列表/編輯界面處理,以及主從表界面處理兩個部分,如下圖所示。

生成的簡單業務表界面,包括分頁列表展示界面,在列表界面中整合查看、編輯、新增、刪除、導入、導出、查詢/高級查詢等功能,整合的編輯界面也是依據資料庫表的信息進行生成的。

列表界面和編輯界面效果如下所示。

而主從表界面生成的效果如下所示。

我們看看生成的Winform列表界面代碼,如下所示。

另外我們把一些常用的處理邏輯放在函數中統一處理,如AddData、EditData、DeleteData、BindData、GetData、ImportData、ExportData等等,如下所示。

 

 在獲取數據的時候,我們根據用戶的條件,構建一個分頁查詢對象傳遞,調用介面獲得數據後,進行分頁控制項的綁定處理即可。

        /// <summary>
        /// 獲取數據
        /// </summary>
        /// <returns></returns>
        private async Task<IPagedResult<CustomerInfo>> GetData()
        {
            CustomerPagedDto pagerDto = null;
            if (advanceCondition != null)
            {
                //如果有高級查詢,那麼根據輸入信息構建查詢條件
                pagerDto = new CustomerPagedDto(this.winGridViewPager1.PagerInfo);
                pagerDto = dlg.GetPagedResult(pagerDto);
            }
            else
            {
                //構建分頁的條件和查詢條件
                pagerDto = new CustomerPagedDto(this.winGridViewPager1.PagerInfo)
                {
                    //添加所需條件
                    Name = this.txtName.Text.Trim(),
                };

                //日期和數值範圍定義
                //年齡,需在CustomerPagedDto中添加 int? 類型欄位AgeStart和AgeEnd
                var Age = new ValueRange<int?>(this.txtAge1.Text, this.txtAge2.Text); //數值類型
                pagerDto.AgeStart = Age.Start;
                pagerDto.AgeEnd = Age.End;

                //創建時間,需在CustomerPagedDto中添加 DateTime? 類型欄位CreationTimeStart和CreationTimeEnd
                var CreationTime = new TimeRange(this.txtCreationTime1.Text, this.txtCreationTime2.Text); //日期類型
                pagerDto.CreateTimeStart = CreationTime.Start;
                pagerDto.CreateTimeEnd = CreationTime.End;
            }

            var result = await BLLFactory<CustomerService>.Instance.GetListAsync(pagerDto);
            return result;
        }

如果是高級查詢,我們則是根據傳入分頁查詢對象的屬性在高級查詢對話框中進行賦值,然後獲得對象後進行查詢獲得記錄的。

 

 在代碼生成工具中,我們根據實際項目的代碼,定義好對應的模板文件,如下所示。

 最後在生成代碼的時候,整合這些NVelocity的模板文件,根據表對象的信息,生成對應的文件供我們開發使用即可。

            #region Model 實體部分

            string entityTemplateFile = ProjectPath + "Templates/Entity.cs.vm";
            var entityAdapter = new SugarEntityAdapter(databaseInfo, selectedTableNames, entityTemplateFile);
            entityAdapter.DirectoryOfOutput = mainSetting.RootNameSpace + "/Core/Modal";
            entityAdapter.Execute();

            #endregion

            #region Interface部分和Application部分

            var appInterface = new SugarServiceInterfaceAdapter(databaseInfo, selectedTableNames, ProjectPath + "Templates/IService.cs.vm", databaseTypeName);
            appInterface.DirectoryOfOutput = mainSetting.RootNameSpace + "/Core/Interface";
            appInterface.Execute();

            var appService = new SugarServiceAdapter(databaseInfo, selectedTableNames, ProjectPath + "Templates/Service.cs.vm", databaseTypeName);
            appService.DirectoryOfOutput = mainSetting.RootNameSpace + "/Core/Service";
            appService.Execute();

            #endregion

            #region Web API Controller 部分

            var controller = new SugarControllerAdapter(databaseInfo, selectedTableNames, ProjectPath + "Templates/Controller.cs.vm", databaseTypeName);
            controller.DirectoryOfOutput = mainSetting.RootNameSpace + "/Controller";
            controller.Execute();

            #endregion            

 

系列文章:

基於SqlSugar的開發框架的循序漸進介紹(1)--框架基礎類的設計和使用

基於SqlSugar的開發框架循序漸進介紹(2)-- 基於中間表的查詢處理

基於SqlSugar的開發框架循序漸進介紹(3)-- 實現代碼生成工具Database2Sharp的整合開發

 

主要研究技術:代碼生成工具、會員管理系統、客戶關係管理軟體、病人資料管理軟體、Visio二次開發、酒店管理系統、倉庫管理系統等共用軟體開發
專註於Winform開發框架/混合式開發框架Web開發框架Bootstrap開發框架微信門戶開發框架的研究及應用
  轉載請註明出處:
撰寫人:伍華聰  http://www.iqidi.com 
    

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • RocketMQ學習 1.基本概念 RocketMQ是阿裡巴巴團隊使用java語言開發的一款分散式消息中間件,是一款低延遲,高可用,擁有海量消息堆積能力和靈活拓展性的消息隊列。 rocketmq的官網:http://rocketmq.apache.org gitee倉庫:https://gitee. ...
  • 多線程筆記(四) 1. Atomic框架包 Atomic包里放著所以保證線程安全的原子類 大致分為7類 基本數據類型的原子操作類 引用類型的原子操作類 數組類型的原子操作類 修改屬性欄位的原子操作類 帶版本的引用類型的原子操作類 增強的基本數據類型的原子操作類 增強操作的公共輔助類 2. Count ...
  • 驗證碼的功能是防止非法用戶惡意去訪問登錄介面而設置的一個功能,今天我們就來看看在前後端分離的項目中,SpringBoot是如何提供服務的。 SpringBoot版本 本文基於的Spring Boot的版本是2.6.7 。 引入依賴 captcha一款超簡單的驗證碼生成,還挺好玩的.還有中文驗證碼,動 ...
  • 作者:等不到的口琴 鏈接:https://www.cnblogs.com/Courage129/p/14446586.html 本文準備圍繞七個點來講網關,分別是網關的基本概念、網關設計思路、網關設計重點、流量網關、業務網關、常見網關對比,對基礎概念熟悉的朋友可以根據目錄查看自己感興趣的部分。 什麼 ...
  • 期中考試題目總結 (1)總結:期中考試主要考察的是點線面類的設計,之前沒有接觸過類,或者說對類沒有什麼很清晰的概念和認知。現在才發現“類”是一個非常強大的工具,可以大大方便我們平時解決問題的過程。期中考試這幾道題目難度適中,很適合我們平時拿來練手,不過也需要抓住各種細節,以防出現一些不該出現的錯誤。 ...
  • 上周遇到個靈異事件,實驗室有兩套環境來搭建redis集群和哨兵,分別是: 第一套環境IP:67(master) 65(salve) 66(salve)第二套環境IP:115(master) 116(salve) 117(salve) 第一天把哨兵搭建好後,兩套環境的主從關係都是一主兩從,但是到了第二 ...
  • 1、線程cpu占用過高 1. top命令發現java程式長時間占用過高的cpu 2. ps H pid,tid,%cpu | grep 進程號PID 3. 使用java工具jstack jstack PID 發現具體線程情況 4. 將tid線程轉換為十六進位去查找具體的線程 5. echo 'oba ...
  • 1.Minio及背景 Minio是一個開源的分散式文件存儲系統,它基於 Golang 編寫,雖然輕量,卻擁有著不錯的高性能,可以將圖片、視頻、音樂、pdf這些文件存儲到多個主機,可以存儲到多個Linux,或者多個Windows,或者多個Mac,Minio中存儲最大文件可以達到5TB。任何類型的文件都 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...