基於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
  • C#TMS系統代碼-基礎頁面BaseCity學習 本人純新手,剛進公司跟領導報道,我說我是java全棧,他問我會不會C#,我說大學學過,他說這個TMS系統就給你來管了。外包已經把代碼給我了,這幾天先把增刪改查的代碼背一下,說不定後面就要趕鴨子上架了 Service頁面 //using => impo ...
  • 委托與事件 委托 委托的定義 委托是C#中的一種類型,用於存儲對方法的引用。它允許將方法作為參數傳遞給其他方法,實現回調、事件處理和動態調用等功能。通俗來講,就是委托包含方法的記憶體地址,方法匹配與委托相同的簽名,因此通過使用正確的參數類型來調用方法。 委托的特性 引用方法:委托允許存儲對方法的引用, ...
  • 前言 這幾天閑來沒事看看ABP vNext的文檔和源碼,關於關於依賴註入(屬性註入)這塊兒產生了興趣。 我們都知道。Volo.ABP 依賴註入容器使用了第三方組件Autofac實現的。有三種註入方式,構造函數註入和方法註入和屬性註入。 ABP的屬性註入原則參考如下: 這時候我就開始疑惑了,因為我知道 ...
  • C#TMS系統代碼-業務頁面ShippingNotice學習 學一個業務頁面,ok,領導開完會就被裁掉了,很突然啊,他收拾東西的時候我還以為他要旅游提前請假了,還在尋思為什麼回家連自己買的幾箱飲料都要叫跑腿帶走,怕被偷嗎?還好我在他開會之前拿了兩瓶芬達 感覺感覺前面的BaseCity差不太多,這邊的 ...
  • 概述:在C#中,通過`Expression`類、`AndAlso`和`OrElse`方法可組合兩個`Expression<Func<T, bool>>`,實現多條件動態查詢。通過創建表達式樹,可輕鬆構建複雜的查詢條件。 在C#中,可以使用AndAlso和OrElse方法組合兩個Expression< ...
  • 閑來無聊在我的Biwen.QuickApi中實現一下極簡的事件匯流排,其實代碼還是蠻簡單的,對於初學者可能有些幫助 就貼出來,有什麼不足的地方也歡迎板磚交流~ 首先定義一個事件約定的空介面 public interface IEvent{} 然後定義事件訂閱者介面 public interface I ...
  • 1. 案例 成某三甲醫預約系統, 該項目在2024年初進行上線測試,在正常運行了兩天後,業務系統報錯:The connection pool has been exhausted, either raise MaxPoolSize (currently 800) or Timeout (curren ...
  • 背景 我們有些工具在 Web 版中已經有了很好的實踐,而在 WPF 中重新開發也是一種費時費力的操作,那麼直接集成則是最省事省力的方法了。 思路解釋 為什麼要使用 WPF?莫問為什麼,老 C# 開發的堅持,另外因為 Windows 上已經裝了 Webview2/edge 整體打包比 electron ...
  • EDP是一套集組織架構,許可權框架【功能許可權,操作許可權,數據訪問許可權,WebApi許可權】,自動化日誌,動態Interface,WebApi管理等基礎功能於一體的,基於.net的企業應用開發框架。通過友好的編碼方式實現數據行、列許可權的管控。 ...
  • .Net8.0 Blazor Hybird 桌面端 (WPF/Winform) 實測可以完整運行在 win7sp1/win10/win11. 如果用其他工具打包,還可以運行在mac/linux下, 傳送門BlazorHybrid 發佈為無依賴包方式 安裝 WebView2Runtime 1.57 M ...