通用查詢解決方案

来源:https://www.cnblogs.com/wanglifeng717/archive/2022/05/29/16324532.html
-Advertisement-
Play Games

資料庫表之間關係: 一對一 (可以看做一對多的特例) 一對多 多對多 下圖將涵蓋了所有關係。 根據restful介面風格,我們最終會落到一個實體上,示例按照b表。其他表同理。 GET https://ip:port/xx/xx/1/0/b 查詢的場景: 只需要b表的某些元素 需要b某些元素,及相關聯 ...


 

 資料庫表之間關係:

  • 一對一 (可以看做一對多的特例)
  • 一對多
  • 多對多

下圖將涵蓋了所有關係。

 

 

根據restful介面風格,我們最終會落到一個實體上,示例按照b表。其他表同理。

GET https://ip:port/xx/xx/1/0/b 

查詢的場景:

  • 只需要b表的某些元素
  • 需要b某些元素,及相關聯的a表某些元素。
  • 需要b某些元素,及a,c,d某些元素。

思路: 通過資料庫的外鍵,自動生成代碼。在新建實體類時,自動查詢關聯的實體。關聯實體查詢一層一層傳導下去。

            通過在返回對象實體上加註解,標識需要返回的欄位,及需要關聯查詢的對象,防止洪泛式關聯對象查詢。

class B{

自身屬性;

關聯的外鍵對象a;

被關聯的對象c集合;

構造方法(){

  查詢自身屬性;

  查詢關聯的外鍵對象a;

  查詢被關聯的對象c集合;

}
}

生成代碼示例如下:

public class BInfo implements Serializable {

    private static final long serialVersionUID = 1L;
    
    public BInfo(){}

    // 主鍵
    @JsonProperty("id")
    private Integer id;
    
    // 名稱
    @JsonProperty("name")
    private String name;
    
    // 詳情
    @JsonProperty("detail")
    private String detail;
    
    // 狀態:0-無效,1-有效,2-編輯
    @JsonProperty("status")
    private Integer status;
    
    // 外鍵關聯實體類(欄位:[ a_id ] 註釋:[  ])
    // 業務實體(關聯表名:tbl_a )
    @JsonProperty("tblAInfo")
    private AInfo aInfo;

    // 業務實體 集合 [tbl_c][b_id]
    @JsonProperty("tblCInfoList")
    private List<CInfo> cInfoList;


    // 構造方法
    public BInfo(SapoDao dao ,B b) throws Exception {
        super();
        //System.err.println("-----new BInfo--------------");
        
        Class<? extends BInfo> thisClass = this.getClass();
        JsonIgnoreProperties annotation = thisClass.getAnnotation(JsonIgnoreProperties.class);
       
        // 外鍵關聯對象:業務實體(tbl_a)
        // 如果註解標註不需要該欄位,則不用查詢該欄位
        if(annotation != null && (! java.util.Arrays.asList(annotation.value()).contains("tblAInfo"))) {
            // 不管狀態,只用外鍵查詢 
            // A a = dao.getAById(b.getAId());
            
           A aResult = null;
        
            // 外鍵欄位不為空才有去查的意義
            if(b.getAId() != null){
            // 組建查詢條件
                A aForQuery = new  A();
           
                 aForQuery.setId(b.getAId());
                // aForQuery.setStatus(A.STATUS_INVALID);
            
                // 查詢,不可為空
                aResult = dao.getA(aForQuery) ;
            }
                        
            // 如果能查該外鍵對應的值,則進行賦值操作
            if(aResult !=null){
            
                // 判斷該欄位是否被註解標識,使用哪個子類
                FkPojo fkano = thisClass.getAnnotation(FkPojo.class);
                
                // 如果沒有被註解標註,需要報錯
                if (fkano == null || fkano.value().length == 0) {
                    throw new Exception(thisClass.getName() + " ->  must have @PkPojo annotation and lenght !=0 ");
                }
                
                // pojo不符合規範也要報錯,註解用冒號分開[類名:全類名]
                Map<String, String> map = new HashMap<String, String>();
                for (String s : fkano.value()) {
                    s = s.trim();
                    String[] split = s.split(":");
                    if (split == null || split.length != 2) {
                        throw new Exception(
                                thisClass.getName() + " ->  @PkPojo annotation format error [pojoName:pojoAllPath] ");
                    }
                    map.put(split[0], split[1]);
                }
                //如果沒有標識子類使用哪一個,則報錯
                if(map.get("AInfo")==null){
                    throw new Exception(thisClass.getName() + " ->   @PkPojo annotation has no class: AInfo");
                }
                // 反射出子類,將子類賦值給該對象。
                Class<?> c1 = Class.forName(map.get("AInfo"));
                Constructor<?> declaredConstructor = c1.getDeclaredConstructor(SapoDao.class, A.class);
                this.aInfo = (AInfo)declaredConstructor.newInstance(dao, aResult);
                    
                }
        }

   
        this.detail=b.getDetail();

   
        this.id=b.getId();

   
        this.name=b.getName();

   
        this.status=b.getStatus();


        // 註解如果將該欄位忽略了,就不需要查了。
        if (annotation != null && (! java.util.Arrays.asList(annotation.value()).contains("tblCInfoList"))) {

            C cForQuery = new C();
            cForQuery.setBId(b.getId());

            List<C> cList = dao.getCListWithNull(cForQuery);

            // 如果查詢的集合是空,也不用繼續往下查了。
            if (cList != null && cList.size() != 0) {
                cInfoList = new ArrayList<CInfo>(cList.size());
                // 判斷該欄位是否被註解標識,使用哪個子類
                FkPojo fkano = thisClass.getAnnotation(FkPojo.class);

                // 如果沒有被註解標註,需要報錯
                if (fkano == null || fkano.value().length == 0) {
                    throw new Exception(thisClass.getName() + " ->  must have @PkPojo annotation and lenght !=0 ");
                }

                // pojo不符合規範也要報錯,註解用冒號分開[類名:全類名]
                Map<String, String> map = new HashMap<String, String>();
                for (String s : fkano.value()) {
                    s = s.trim();
                    String[] split = s.split(":");
                    if (split == null || split.length != 2) {
                        throw new Exception(
                                thisClass.getName() + " ->  @PkPojo annotation format error [pojoName:pojoAllPath] ");
                    }
                    map.put(split[0], split[1]);
                }
                // 如果沒有標識子類使用哪一個,則報錯
                if (map.get("CInfo") == null) {
                    throw new Exception(
                            thisClass.getName() + " ->   @PkPojo annotation has no class: CInfo");
                }
                // 反射出子類,將子類賦值給該對象。
                Class<?> c1 = Class.forName(map.get("CInfo"));
                Constructor<?> declaredConstructor = c1.getDeclaredConstructor(SapoDao.class, C.class);
                
                // 迴圈新建對象,將對象加入到集合中。
                for (C item : cList) {
                    cInfoList.add((CInfo) declaredConstructor.newInstance(dao, item));
                }
            }
        }

    
    }


    /**
     * 設置
     * 主鍵
     * 的方法
     *
     * @param id 主鍵
     */
    public void setId(Integer id){
        this.id = id;
    }
    
    /**
     * 獲取
     * 主鍵
     * 的方法
     *
     * @return   主鍵
     */
    public Integer getId(){
        return id;
    }

    /**
     * 設置
     * 名稱
     * 的方法
     *
     * @param name 名稱
     */
    public void setName(String name){
        this.name = name;
    }
    
    /**
     * 獲取
     * 名稱
     * 的方法
     *
     * @return   名稱
     */
    public String getName(){
        return name;
    }

    /**
     * 設置
     * 詳情
     * 的方法
     *
     * @param detail 詳情
     */
    public void setDetail(String detail){
        this.detail = detail;
    }
    
    /**
     * 獲取
     * 詳情
     * 的方法
     *
     * @return   詳情
     */
    public String getDetail(){
        return detail;
    }

    /**
     * 設置
     * 狀態:0-無效,1-有效,2-編輯
     * 的方法
     *
     * @param status 狀態:0-無效,1-有效,2-編輯
     */
    public void setStatus(Integer status){
        this.status = status;
    }
    
    /**
     * 獲取
     * 狀態:0-無效,1-有效,2-編輯
     * 的方法
     *
     * @return   狀態:0-無效,1-有效,2-編輯
     */
    public Integer getStatus(){
        return status;
    }

    /**
     * 設置
     * 業務實體(tbl_a )
     * 的方法
     *
     * @param 業務實體(tbl_a )
     */
    public AInfo setAInfo(AInfo aInfo){
        this.aInfo = aInfo;
        return this;
    }
    
    /**
     * 獲取
     * 業務實體(tbl_a )
     * 的方法
     *
     * @return 
     */
    public AInfo getAInfo(){
        return aInfo;
    }


    
    public void setCInfoList(List<CInfo> cInfoList){
        this.cInfoList = cInfoList;
    }
    
    
    public List<CInfo> getCInfoList(){
        return cInfoList;
    }


}
B實體對象
@JsonIgnoreProperties({
"id",
"name",
"detail",
"status",
"tblAInfo",
"tblCInfoList"
})

@FkPojo({
"CInfo:classQualifiedName",
"AInfo:classQualifiedName"
})
public class BInfoxx extends BInfo{

    private static final long serialVersionUID = 1L;
    
    public BInfoxx(){}
    
    public BInfoxx(SapoDao dao,B b) throws Exception{
        super(dao,b);
    }
}
B實體返回對象

 

生成代碼工具如下:

   1 DROP PROCEDURE IF EXISTS `print_pojo`;
   2 DELIMITER $
   3 CREATE  PROCEDURE `print_pojo`()
   4 BEGIN
   5 
   6 SET  group_concat_max_len = 4294967295;
   7 
   8 -- 表名去除那些首碼
   9 -- SET @noStrInTbl='tbl_ams';
  10 SET @noStrInTbl='tbl';
  11 -- 通用dao層類名,
  12 SET @common_dao_name='SapoDao';
  13 -- domain類名尾碼
  14 SET @domain_suffix='Info';
  15 
  16 SET @domain_prefix='tbl_sapo';
  17 
  18 
  19 
  20 -- ######################begin:基礎信息表維護###################
  21 
  22 -- 保存所有表及表的所有欄位
  23 DROP TABLE if EXISTS all_col_table;
  24 CREATE table if not exists all_col_table(
  25 `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主鍵',
  26 tbl_name VARCHAR(256)    COMMENT '表名:tbl_sapo_admin_account',
  27 tbl_name_comment  VARCHAR(256)   COMMENT '表註釋',
  28 
  29 tbl_name_upper_camel VARCHAR(1024) COMMENT '表名大寫駝峰:SapoAdminAccount',
  30 tbl_name_lower_camel VARCHAR(1024) COMMENT '表名小寫駝峰:sapoAdminAccount',
  31 
  32 domain_tbl_name_upper_camel VARCHAR(1024) COMMENT 'doamin層表名駝峰:SapoAdminAccountInfo',
  33 domain_tbl_name_lower_camel VARCHAR(1024) COMMENT 'domain層表名引用駝峰:sapoAdminAccountInfo',
  34 
  35 col VARCHAR(256)   COMMENT '欄位名:create_time',
  36 if_fk VARCHAR(512) NOT NULL DEFAULT 'no' COMMENT '外鍵標誌,yes=外鍵',
  37 col_comment VARCHAR(512) COMMENT '欄位註釋',
  38 col_lower_camel VARCHAR(256) COMMENT '欄位駝峰形式:createTime',
  39 col_upper_camel VARCHAR(256) COMMENT '欄位駝峰首字母大寫:CreateTime',
  40 
  41 col_type VARCHAR(256) COMMENT '欄位類型,datetime,int',
  42 java_type VARCHAR(256) COMMENT 'java類型,LocalDateTime,Integer',
  43 
  44 col_setter VARCHAR(256)   COMMENT 'setter模式:setCreateTime',
  45 col_getter VARCHAR(256)   COMMENT 'getter模式:getCreateTime',
  46 
  47 json_property VARCHAR(256) COMMENT 'json_property欄位',
  48 
  49 PRIMARY KEY (`id`) ,
  50 index  (`tbl_name`,col) ,
  51 INDEX idx_1(col)
  52 ) ENGINE=InnoDB DEFAULT CHARSET=UTF8;
  53 
  54 
  55 -- 外鍵臨時表
  56 DROP TABLE if exists fk_def;
  57 CREATE TABLE if not exists fk_def as
  58     SELECT
  59         t.TABLE_NAME AS tbl_name,
  60         k.column_name AS col,
  61         k.REFERENCED_TABLE_NAME AS rf_tbl_name,
  62         k.REFERENCED_COLUMN_NAME AS rf_col 
  63     FROM
  64         information_schema.TABLE_CONSTRAINTS t
  65         JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE k 
  66         ON t.CONSTRAINT_NAME = k.CONSTRAINT_NAME 
  67         AND t.TABLE_NAME = k.TABLE_NAME 
  68         AND t.CONSTRAINT_SCHEMA = k.CONSTRAINT_SCHEMA 
  69     WHERE
  70         t.CONSTRAINT_TYPE = 'FOREIGN KEY' 
  71         AND t.table_schema = DATABASE();
  72         
  73 ALTER TABLE `fk_def`
  74     ADD INDEX `idx1` (tbl_name,col);
  75     
  76 ALTER TABLE `fk_def`
  77     ADD INDEX `idx2` (rf_tbl_name,rf_col);
  78 
  79 
  80 -- select * from fk_def ;
  81 -- ######################end:基礎信息表維護###################
  82 
  83 
  84 -- 將本庫中所有表及所有欄位插入表中: tbl_name,tbl_name_comment,col,col_comment,col_type
  85 INSERT INTO all_col_table(tbl_name,tbl_name_comment,col,col_comment,col_type) 
  86 SELECT 
  87     t1.table_name, t2.TABLE_COMMENT,t1.column_name ,t1.COLUMN_COMMENT,t1.DATA_TYPE
  88 FROM
  89     information_schema.COLUMNS t1 JOIN information_schema.tables t2 ON t1.TABLE_NAME=t2.TABLE_NAME     
  90 WHERE
  91       t1.table_schema= DATABASE() AND t1.TABLE_NAME LIKE 'tbl_%' ORDER BY t1.TABLE_NAME,t1.ORDINAL_POSITION;
  92 
  93 -- java類型轉換
  94 UPDATE all_col_table SET java_type=
  95 case  col_type 
  96     when 'datetime' then 'LocalDateTime' 
  97     when 'tinyint'  then 'Byte' 
  98     when 'bigint'   then 'Long' 
  99     when 'int'      then 'Integer' 
 100     when 'varchar'  then 'String' 
 101 END;
 102 
 103 -- 欄位轉駝峰
 104 UPDATE all_col_table SET col_lower_camel =CONCAT_WS('',REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(col, '_z', 'Z'), '_y', 'Y'), '_x', 'X'), '_w', 'W'), '_v', 'V'), '_u', 'U'), '_t', 'T'), '_s', 'S'), '_r', 'R'), '_q', 'Q'), '_p', 'P'), '_o', 'O'), '_n', 'N'), '_m', 'M'), '_l', 'L'), '_k', 'K'), '_j', 'J'), '_i', 'I'), '_h', 'H'), '_g', 'G'), '_f', 'F'), '_e', 'E'), '_d', 'D'), '_c', 'C'), '_b', 'B'), '_a', 'A'),'_','') 
 105 ,'');
 106 UPDATE all_col_table SET col_upper_camel =CONCAT_WS('',REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(CONCAT_WS('','_',col), '_z', 'Z'), '_y', 'Y'), '_x', 'X'), '_w', 'W'), '_v', 'V'), '_u', 'U'), '_t', 'T'), '_s', 'S
              
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 下表數據,是歷時四年,不定期記錄下的本博積分與排名情況。 咋一看,是個挺簡單的數據表,似乎依此可以輕鬆地搞出個增長曲線圖之類的東東,再分析點什麼結論出來。但再仔細研究一下,發現不那麼回事,這裡面還是挺複雜的。 突然有種感覺,這和軟體開發何期的相似。有多少次,剛聽到一個新需求時,會感覺這不是個什麼事, ...
  • 緊急更新第二彈,然後就剩下最後一彈,也就是整個前臺的項目 一.購物車 1.加入購物車(新知識點) 加入到購物車是需要介面操作的,因為我們需要將用戶的加入到購物車的保存到伺服器資料庫,你的賬號後面才會在你自己的購物車看到,所以這裡要先寫介面 然後vuex三部曲, 返回來的數據沒有data,就是告訴你成 ...
  • jQuery jQuery是什麼 jQuery是一個快速、簡潔的JavaScript框架,是繼Prototype之後又一個優秀的JavaScript代碼庫(或JavaScript框架)。jQuery設計的宗旨是“write Less,Do More”,即倡導寫更少的代碼,做更多的事情。它封裝Java ...
  • 這幾天一直都在做項目,只是沒有上傳上來,即將把前臺項目完結了。現在開始更新整個前臺的部分 一.麵包屑處理 1.分類操作 點擊三級聯動進入搜索產生麵包屑,直接取參數中的name即可 點擊x怎麼幹掉這個麵包屑,直接讓其v-if為這個name,如果點擊x就把name清空 清空還沒完,清空應該再發一次請求, ...
  • 本章是系列文章的第五章,介紹了指針分析方法。指針分析在C/C++語言中非常重要,分析的結果可以有效提升指針的優化效率。 本文中的所有內容來自學習DCC888的學習筆記或者自己理解的整理,如需轉載請註明出處。周榮華@燧原科技 5.1 概念 指針是許多重要編程語言的特性之一 指針的使用,可以避免大量的數 ...
  • 第四章: 設計與聲明 ###18. 讓介面更容易被正確使用,不易被誤用 將你的class的public介面設計的符合class所扮演的角色,必要時不僅對傳參類型限制,還對傳參的值域進一步限制。 ###19. 設計class猶如設計type 內置類型如int、float等,本質也是一個class,用戶 ...
  • 前言 還記得你第一次遇到「線程安全」這個詞的時候嗎? 我第一次遇到線程安全這個詞是在學習多線程併發操作的時候,看到人家文章里出現這個詞,還有說各種線程安全的類,但是一開始並不理解線程安全是什麼意思,也沒去深究線程怎樣是安全的?怎樣是不安全的?只是腦子裡接收了這麼一個詞。 線程安全是多線程編程時的計算 ...
  • JVM 是Java的基石,Java從業者需要瞭解。JVM不是一個新的知識,網上文章很多,本篇的不同之處在於參考一手資料、內容經過反覆推敲。本文將會有篩選地研究JVM的精華部分,至少達到準系統架構師夠用的程度。本篇主要分享學習Java Class文件以及類載入器CLassLoader的知識。 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...