Spring JPA 动态列查询有什么好的思路 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
leiuu
V2EX    Java

Spring JPA 动态列查询有什么好的思路

  •  
  •   leiuu 2022-06-06 15:28:35 +08:00 3912 次点击
    这是一个创建于 1222 天前的主题,其中的信息可能已经有所发展或是发生改变。

    例如数据库表可能存放有 30 列,本身是列式存储。

    实际的查询场景可能每次查询 5 列,且组合可能不一样。

    如果用 jpa projections 可能面临需要定义一堆 entiny ,组合数爆炸。

    30 条回复    2022-07-22 21:19:41 +08:00
    bz5314520
        1
    bz5314520  
       2022-06-06 15:35:53 +08:00
    楼主是想说,会定义太多的 dto?
    leiuu
        2
    leiuu  
    OP
       2022-06-06 15:38:51 +08:00
    @bz5314520 对的 动态列每一个组合可能都需要一个 dto 不太优雅
    Vaspike
        3
    Vaspike  
       2022-06-06 15:50:53 +08:00
    @leiuu #2
    DTO 处:返回的数据字段换成 Map 类型会不会好些
    JPA 处: 我还真忘了 JPA 返回 Map 类型是不是一定要写 native sql ,OP 自己评估下吧
    Tenlearn
        4
    Tenlearn  
       2022-06-06 15:51:11 +08:00
    这和 jpa 有什么关系,映射到对象不就这样吗
    iosyyy
        5
    iosyyy  
       2022-06-06 15:51:22 +08:00
    用 QueryDsl 试试
    sujin190
        6
    sujin190  
       2022-06-06 15:54:44 +08:00   3
    @Query("select new com.demo.ArticleQueryDto(a.id, a.viewCount) from t_article a")

    Query 声明的时候 select 用 new 啊,然后写不同的参数的构造函数就是了呗,转换 sql 语句的时候似乎只会 select 你访问的属性字段,似乎不会再 select 所有字段了
    suman
        7
    suman  
       2022-06-06 16:08:27 +08:00
    JPA Specification
    EastLord
        8
    EastLord  
       2022-06-06 16:29:22 +08:00
    querydsl 如何
    bz5314520
        9
    bz5314520  
       2022-06-06 16:37:56 +08:00
    @leiuu 我没觉得不优雅,你这样查询估计也是一个接口对应一个前端视图,静态类型检查反而方便调试。这种生成 dto 的体力活,用 IDEA 的插件 JPA BUDDY 生成就行。
    leiuu
        10
    leiuu  
    OP
       2022-06-06 17:11:51 +08:00
    @Vaspike 这是个方法 但估计得用 createQuery 写 nativeSql

    @Tenlearn

    @iosyyy QueryDsl 很强大 用 DSL 可以实现

    @suman 可以解决动态 where 但 select column 不行的

    @sujin190 哈哈 666 的操作可行 !

    @bz5314520 理解了。这也是一个法子哈。静态定义理解代价小。但总觉得需要维护很多类, 如果有更新会比较麻烦。
    leiuu
        11
    leiuu  
    OP
       2022-06-06 17:13:45 +08:00
    @EastLord 可行! Dsl 可以搞定。 哈哈,其实想知道「更 jpa 」的写法。目前看 new object 不错。
    sky857412
        12
    sky857412  
       2022-06-06 17:16:34 +08:00
    hakr
        13
    hakr  
       2022-06-06 17:23:32 +08:00
    PopRain
        14
    PopRain  
       2022-06-06 17:28:56 +08:00
    这好像和我之前的问题类似:
    t/843880#reply10
    nothingistrue
        15
    nothingistrue  
       2022-06-06 17:31:11 +08:00   1
    你这个返回的列是动态的,这就算到 SQL 那里也不是动态查询,你每次动态选择的列,对 SQL 执行屁影响都没有。WHERE 条件每次都是随机生成的,这才是 ORM 或者 SQL 查询上的动态查询。

    请先把你的动态查询给分成两个过程。首先,WHERE 条件动态是一个过程,用 JPA 的 Specification 。然后,返回列的动态是一个过程,这个简单的很,你不论如何都查询出来一个 Entity ( JPA 的要求也必须是一个 Entity 对应一套表),然后在将这个 Entity ,根据接口返回的需要,返回不同的 DTO/VO ,或者仅返回指定字段的 Map (看你的场景,返回哪些列是用得时候才知道的,这样返回 MAP 更合适)。
    Seney
        16
    Seney  
       2022-06-06 17:33:40 +08:00
    除了上面 dsl/jpql, 还可以用投射,另外定义个 interface 相当于 dto 来接受结果集
    leiuu
        17
    leiuu  
    OP
       2022-06-06 17:59:55 +08:00
    @nothingistrue 对理解有帮助 这里之所以说是动态,因为默认是全部列返回,如果后端是列存数据库性能就会比较差
    @Seney 你和楼上头像好像。dto 的方法可以,但可能一个 entity 我的场景中可以衍生出 15 个 dto 。他们只有个别字段不一样。
    leiuu
        18
    leiuu  
    OP
       2022-06-06 18:03:46 +08:00
    @sky857412 Nope !

    @hakr CriteriaQuery 可以实现


    @PopRain 场景很相似!
    duyaofei
        19
    duyaofei  
       2022-06-07 07:38:54 +08:00
    感觉 jdbctemplate 更适合啊,这场景
    zed1018
        20
    zed1018  
       2022-06-07 08:56:04 +08:00
    我觉得你这个其实更应该是 graphQL ?
    KingOfUSA
        21
    KingOfUSA  
       2022-06-07 09:34:33 +08:00
    @leiuu 用下我的这个库吧 ( https://github.com/ksprider/Surgical ),可以解决一个 entity 对应 n 多种组合的 dto 的场景。
    KevinBlandy
        22
    KevinBlandy  
       2022-06-07 14:53:27 +08:00   1
    Spring Data JPA + QueryDsl 。强烈推荐。投影查询,对象封装,JOIN 检索,UPDATE 部分列。要多舒服有多舒服。

    我写过一个 QueryDsl 的案例,你可以看看。

    [https://springboot.io/t/topic/4424]( https://springboot.io/t/topic/4424)
    leiuu
        23
    leiuu  
    OP
       2022-06-07 16:27:11 +08:00
    @KevinBlandy 手动赞一下 querydsl 很强大 用了 querydsl 是不是一般都不需要 dao 层了 service 层似乎直接就完成工作了
    KevinBlandy
        24
    KevinBlandy  
       2022-06-07 17:45:06 +08:00
    @leiuu 是的。抽象一下,直接在 Controller 就可以通过 Lambda 操作数据库。很方便,不需要写 Service ,Mapper ,xml 以及一堆堆的映射。
    RookieRicardo
        25
    RookieRicardo  
       2022-06-07 17:50:11 +08:00
    @KevinBlandy

    @leiuu

    dao 层是为了分层才设计出来的,真正的业务,哪有一条 CRUD 就结束的。
    KevinBlandy
        26
    KevinBlandy  
       2022-06-07 17:55:05 +08:00
    @RookieRicardo 看情况呗,我的业务只是为了更新一个字段。我没必要写过 Service ,写个 Dao 。

    ```java
    public void handler (){
    this.service.apply(query -> {
    return query.update(user).set(user.enabled, false).where(user.id.eq(1)).exec();
    })
    }
    ```
    RookieRicardo
        27
    RookieRicardo  
       2022-06-07 17:58:11 +08:00
    @KevinBlandy 如果没有编程规范的话 怎么样都行
    leiuu
        28
    leiuu  
    OP
       2022-06-07 18:59:29 +08:00
    @RookieRicardo 同意 需要依据团队规范,但这里不知道有没有好的实践方式。

    QueryDsl 很灵活,service 涉及多个 entiny 也可以支持 。可能很多需求在 service 层写 dsl 就实现了。所以会纠结是否需要独立抽象 dao 层。

    ```java
    QPerson person = QPerson.person;
    List<Person> persOns= query.from(person)
    .where(person.firstname.eq(firstname))
    .orderBy(person.surname.desc())
    .list(person);

    ...
    ```
    kongkongye
        29
    kongkongye  
       2022-07-22 19:15:48 +08:00
    @nothingistrue 有个问题,如果返回 map 的话是不对 swagger 之类的不太友好,前端单看 swagger 接口说明不知道会返回啥字段,不过好像也没啥好办法
    nothingistrue
        30
    nothingistrue  
       2022-07-22 21:19:41 +08:00
    严格意义上来说,swagger 的接口定义是要自己写 yaml ,跟你后端定义的对象无关的。能够自动根据 Java 类生成 Swagger 接口定义的,是 Springfox-swagger 插件。而这个插件,是允许你通过注解的方式用自己的定义覆盖默认定于一的,所以及时使用 Map 仍然能够不影响 swagger 这类的接口定义,只是需要多做一些注解 /注释性的工作。

    当然,用 Map 不影响,不是鼓励 Map ,首选仍然是特定的类。楼主这里推荐用 Map ,是因为它返回内容当中的字段是不固定的,有可能还是前端要啥后端返回啥,这时候没法定义特定的类了(或者说定义的类就用一次,太浪费),用 Map + 注释 /注解会更省事。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2379 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 15:41 PVG 23:41 LAX 08:41 JFK 11:41
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86