jpa+querydsl的平替國產easy-query最好用的orm

薛家明發表於2024-08-02

jpa+querydsl的平替國產easy-query最好用的orm

一款國產最強java orm,完美支援可控強型別dsl,外加完美支援物件模型篩選拉取的orm,擁有非常智慧的include(s)一對多、一對一、多對多、多對一實現的orm

地址github: https://github.com/dromara/easy-query

地址gitee: https://gitee.com/dromara/easy-query

文件地址: http://www.easy-query.com/easy-query-doc/

一款擁有高度抽象遮蔽各大資料庫方言的orm,讓你的換庫如魚得水非常方便,整合實現各種資料庫方言的使用,讓你輕鬆應對各種需求,並且在物件模型上讓你可以省去大把時間在多對多之間來回篩選

場景1

使用者和角色,角色和選單我們都知道這是最最最基礎的一個場景,其中使用者和角色是多對多,角色和選單也是多對多

往往普通orm在演示的時候只會對當前表的屬性進行篩選排序等操作,但是如果遇到查詢主表篩選條件是子表那麼大部分orm都是很麻煩的,想寫出來往往是非常的費時費力並且還不支援動態條件

  • 篩選使用者
  • 條件角色包含管理員的
 List<SysUser> managers = easyEntityQuery.queryable(SysUser.class)
                .where(s -> {
                    //篩選條件為角色集合裡面有角色名稱叫做管理員的
                    s.roles().any(role -> {
                        role.name().eq("管理員");
                    });
                }).toList();

什麼你還嫌麻煩,那麼如果你只有一個條件可以對roles進行展開來斷言

當且僅當一(多)對多的時候那麼關聯模型將是集合的時候如果希望斷言是否存在集合內的單一屬性條件判斷可以透過flatElement展開屬性直接判斷

        List<SysUser> managers = easyEntityQuery.queryable(SysUser.class)
                .where(s -> {
                    //篩選條件為角色集合裡面有角色名稱叫做管理員的
                    s.roles().flatElement().name().eq("管理員");
                }).toList();

我們來看看具體執行的sql

-- 第1條sql資料
SELECT
    t.`id`,
    t.`company_id`,
    t.`name`,
    t.`age`,
    t.`create_time` 
FROM
    `t_user` t 
WHERE
    EXISTS (
        SELECT
            1 
        FROM
            `t_role` t1 
        WHERE
            EXISTS (
                SELECT
                    1 
                FROM
                    `t_user_role` t2 
                WHERE
                    t2.`role_id` = t1.`id` 
                    AND t2.`user_id` = t.`id` LIMIT 1
            ) 
            AND t1.`name` = '管理員' LIMIT 1
        )

如果你要執行這個sql還要動態條件那麼真的非常讓人絕望
有人說如何做動態條件呢

   List<SysUser> managers = easyEntityQuery.queryable(SysUser.class)
                .where(s -> {
                    //篩選條件為角色集合裡面有角色名稱叫做管理員的
                   if(false){
                       s.roles().any(role -> {
                           role.name().eq("管理員");
                       });
                   }
                }).toList();

是的你沒看錯就這麼簡簡單單的一個條件就可以讓其支援動態多對多篩選,那麼如果這個條件是false那麼生成的sql將是怎麼樣的呢

SELECT `id`,`company_id`,`name`,`age`,`create_time` FROM `t_user`

是不是被easy-query這麼智慧的條件處理驚訝到了,如果你需要手寫那麼將會是災難何況還有邏輯刪除和各種攔截器

那麼我們再來看看下一個場景

場景2

使用者和角色和選單

分別是多對多 和多對多

  • 篩選使用者
  • 條件是使用者擁有/admin的選單
  List<SysUser> managers = easyEntityQuery.queryable(SysUser.class)
                .where(s -> {
                    //篩選條件為角色集合裡面的選單是/admin
                    s.roles().any(role -> {
                        role.menus().any(menu->{
                            menu.route().eq("/admin");
                        });
                    });
                }).toList();

哇哦簡直完美簡潔,什麼你覺得還是太複雜了那麼我們再將其簡化

      List<SysUser> managers = easyEntityQuery.queryable(SysUser.class)
                .where(s -> {
                    //篩選條件為角色集合裡面的選單是/admin
                    s.roles().flatElement().menus().any(menu->{
                        menu.route().eq("/admin");
                    });
                }).toList();


//上下兩種都可以,因為我們沒有對roles進行條件篩選
//所以可以直接透過兩次flatElement來展開元素直接斷言選單


        List<SysUser> managers = easyEntityQuery.queryable(SysUser.class)
                .where(s -> {
                    //篩選條件為角色集合裡面的選單是/admin
                    s.roles().flatElement().menus().flatElement().route().eq("/admin");
                }).toList();

接下來我們再來看看生成的sql


-- 第1條sql資料
SELECT
    t.`id`,
    t.`company_id`,
    t.`name`,
    t.`age`,
    t.`create_time` 
FROM
    `t_user` t 
WHERE
    EXISTS (
        SELECT
            1 
        FROM
            `t_role` t1 
        WHERE
            EXISTS (
                SELECT
                    1 
                FROM
                    `t_user_role` t2 
                WHERE
                    t2.`role_id` = t1.`id` 
                    AND t2.`user_id` = t.`id` LIMIT 1
            ) 
            AND EXISTS (
                SELECT
                    1 
                FROM
                    `t_menu` t3 
                WHERE
                    EXISTS (
                        SELECT
                            1 
                        FROM
                            `t_role_menu` t4 
                        WHERE
                            t4.`menu_id` = t3.`id` 
                            AND t4.`role_id` = t1.`id` LIMIT 1
                    ) 
                    AND t3.`route` = '/admin' LIMIT 1
                ) LIMIT 1
        )

我已經麻瞭如果沒有orm簡直不敢想

場景3

  • 查詢使用者
  • 條件是使用者擁有的角色數量不少於3個的
        List<SysUser> managers = easyEntityQuery.queryable(SysUser.class)
                .where(s -> {
                    //篩選條件為角色集合的數量大於等於3個
                    s.roles().count().ge(3L);
                }).toList();

非常符合直覺
生成的sql呢是怎麼樣的


-- 第1條sql資料
SELECT
    t.`id`,
    t.`company_id`,
    t.`name`,
    t.`age`,
    t.`create_time` 
FROM
    `t_user` t 
WHERE
    (
        SELECT
            COUNT(*) 
        FROM
            `t_role` t1 
        WHERE
            EXISTS (
                SELECT
                    1 
                FROM
                    `t_user_role` t2 
                WHERE
                    t2.`role_id` = t1.`id` 
                    AND t2.`user_id` = t.`id` LIMIT 1
            )
        ) >= 3

場景4

  • 查詢角色
  • 條件是角色關聯的使用者平均年齡是15歲或者姓金的至少有2位以上
List<SysRole> roles = easyEntityQuery.queryable(SysRole.class)
                .where(role -> {
                    role.or(()->{
                        role.users().avg(u->u.age()).ge(BigDecimal.valueOf(15));
                        role.users().where(u->u.name().likeMatchLeft("金")).count().ge(2L);
                    });
                }).toList();

讓我們來看看生成的sql

-- 第1條sql資料
SELECT
    t.`id`,
    t.`name`,
    t.`create_time` 
FROM
    `t_role` t 
WHERE
    (
        IFNULL((SELECT
            AVG(t1.`age`) 
        FROM
            `t_user` t1 
        WHERE
            EXISTS (SELECT
                1 
            FROM
                `t_user_role` t2 
            WHERE
                t2.`user_id` = t1.`id` 
                AND t2.`role_id` = t.`id` LIMIT 1)),0) >= '15' 
        OR (
            SELECT
                COUNT(*) 
            FROM
                `t_user` t4 
            WHERE
                EXISTS (
                    SELECT
                        1 
                    FROM
                        `t_user_role` t5 
                    WHERE
                        t5.`user_id` = t4.`id` 
                        AND t5.`role_id` = t.`id` LIMIT 1
                ) 
                AND t4.`name` LIKE '金%'
            ) >= 2
    )

不要看這個sql這麼複雜這可是多對多下的查詢正常人壓根沒辦法寫這種sql

最後

這邊展示了非常強大的OLTP查詢模式,OLAP也是非常強大可以group+join,實現from (匿名sql) 也可以join (匿名sql)

一款具有強型別OLTP+OLAP的完美解決方案,並且完美支援mybatis系列的任意架構逐步構建遷移,不會產生任何衝突,因為easy-query本身就是零依賴,並且完全免費,完全開源(包括文件!!!包括文件!!!包括文件!!!)

我相信easy-query是一款可以完完全全打動您的ORM作品,也是全java唯一一款全sql替代性產品

相關文章