请教,spring data jpa 中,分页查询返回多个表字段应该怎么处理? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
palmers
V2EX    Java

请教,spring data jpa 中,分页查询返回多个表字段应该怎么处理?

  •  
  •   palmers 2017-01-11 16:22:08 +08:00 15252 次点击
    这是一个创建于 3271 天前的主题,其中的信息可能已经有所发展或是发生改变。

    继承了 PagingAndSortingRepository , 这个接口提供了 Page<T> findAll(Pageable var1); 方法 我需要自定义 sql 然后返回字段是从两个表中挑选出来的. sql 类似这样的:

    select a.name ax , a.cd cd , b.name ax from a left join b on b.id = d.bid 

    我需要在上面 sql 返回结果的基础上分页和排序, 请问大家怎么处理这个问题?

    谢谢大家!!!

    第 1 条附言    2017-01-12 14:56:43 +08:00

    最终查询出来啦! 但是很不方便,实现步骤如下: 关联查询表如下:

    TA 字段:

    • id
    • name
    • bid
    • time

    TB 字段:

    • id
    • name

    然后查询sql这样:

    select a.name as name, a.time as time, b.name as bname from TA a left join TB b on b.id = a.bid 

    首先需要在TA实体类上注解SqlResultSetMapping,手动映射返回字段描述,像这样:

    @SqlResultSetMapping( name = "view", classes = { @ConstructorResult( targetClass = TA.class, columns={ @ColumnResult(name = "name",type = String.class), @ColumnResult(name = "time",type = Date.class), @ColumnResult(name = "bname",type = String.class) } ) } ) 

    这段映射对象必须是一个entity 否则启动jpa扫描报错,异常信息大概这样:

    Unknown SqlResultSetMapping [foo] 

    然后调用 createNativeQuery 方法执行sql 同时指定映射对象名[字符串名] 类似这样:

    //需要手动注入 `EntityManager` Query query = em.createNativeQuery(sql, "view"); //然后获取结果集 query.getResultList(); 

    这样就可以得到指定对象的结果集了. 业务功能确实实现了,但是这种实现好难受, 声明的 SoccerGuessingRepository 在这里成了摆设, 而且分页也需要自己写了, 太别扭了!!!!!

    请问大家还有别的解决方案吗?

    第 2 条附言    2017-01-12 15:07:18 +08:00

    上面解决办法参考链接在这里

    而且需要提供返回列对应的对象的包含全部返回咧的构造方法.

    37 条回复    2019-06-25 23:37:50 +08:00
    sdandroid
        1
    sdandroid  
       2017-01-11 16:55:35 +08:00
    做视图
    palmers
        2
    palmers  
    OP
       2017-01-11 17:02:09 +08:00
    @sdandroid 你的意思要在数据库中新建一个视图吗? 麻烦你给个比较详细的方案 谢谢了
    Powered
        3
    Powered  
       2017-01-11 17:09:28 +08:00 via iPhone
    我没看懂需求。。。
    mercurylanded
        4
    mercurylanded  
       2017-01-11 17:10:26 +08:00   1
    换 mybatis
    Charkey
        5
    Charkey  
       2017-01-11 17:11:26 +08:00
    @mercurylandd 同意。 23333333333333333
    palmers
        6
    palmers  
    OP
       2017-01-11 17:22:51 +08:00
    @Powered 我的需求是这样的, 使用 spring data jpa 分页查询, 然后返回的数据是两个表部分字段的组合对象
    palmers
        7
    palmers  
    OP
       2017-01-11 17:23:22 +08:00
    @mercurylanded 是啊 如果能换, 我肯定换了 绝对没这么麻烦
    tedzhou1221
        8
    tedzhou1221  
       2017-01-11 17:34:41 +08:00
    虽然我明白你的意思,但想了半小时办法,还是没想到~~

    其实楼上的兄弟说,用视图搞也是可以的。
    tedzhou1221
        9
    tedzhou1221  
       2017-01-11 17:36:58 +08:00
    唉,说换 mybatis 的兄弟,不知道是怎么想的。

    像我这种公司打杂的,公司项目架构,能说换就换?
    Sharuru
        10
    Sharuru  
       2017-01-11 18:12:11 +08:00
    架构里有其他辅助方法么?比如常见的命名像什么 builder , executor 之类的,可以快速生成 SQL 。

    如果没有类似的 helper ,直接手写 JPQL 也是可以的。
    AlisaDestiny
        11
    AlisaDestiny  
       2017-01-11 18:30:41 +08:00
    我现在做的项目是用 springboot ,现在刚开始,估计以后也会遇到你这个问题,先收藏了。(之前用的 mybatis 很好解决)
    palmers
        12
    palmers  
    OP
       2017-01-11 18:37:37 +08:00
    @AlisaDestiny ......................
    palmers
        13
    palmers  
    OP
       2017-01-11 18:41:11 +08:00
    @Sharuru JPQL 怎么解决 两个表部分字段组合为第三个对象返回的情况呢? 麻烦详细说说 谢谢了
    mercurylanded
        14
    mercurylanded  
       2017-01-11 18:50:55 +08:00
    模型重新写做字段冗余,或者多查几次结果合并起来。
    RadishWind
        15
    RadishWind  
       2017-01-11 18:57:06 +08:00
    1.视图 create view 名字 as + 你的 sql 语句
    2.子查询
    3.直接 limit
    caixiexin
        16
    caixiexin  
       2017-01-11 19:04:29 +08:00 via Android
    就是因为这个,我不喜欢用 hibernate 这类 orm
    srx1982
        17
    srx1982  
       2017-01-11 19:34:05 +08:00
    首先我有个疑问,你的 sql 里怎么会出现 d 表?前边是 a 表啊
    我按照我目前的理解给一个答案你看看
    1.新建个类 ABResult ,类全名 com.abc.ABResult ,写好构造方法 public ABResult(String aName, String aCd, String bName)
    2.JPQL:"SELECT new com.abd.xxResult(a.name, a.cd, b.name) FROM TableA a LEFT JOIN FETCH a.b"
    3.你的 T 就是 ABResult
    这种 new 的写法我们一直在用,不知道合不合你的需求。
    Cbdy
        18
    Cbdy  
       2017-01-11 19:46:17 +08:00 via Android
    注入实体管理器,直接执行 SQL 。参考 Spring in action
    palmers
        19
    palmers  
    OP
       2017-01-11 19:54:04 +08:00
    @srx1982 嗯嗯 非常感谢! 我今天也找到你说的这种方案了! 但是测试失败了,我明天再详细看看。 不知道是不是因为 a b 两个表实体没有关联关系?

    不好意思 ,我 sql 写粗心了, 应该是 left join b on b.id = a.bid
    palmers
        20
    palmers  
    OP
       2017-01-11 19:55:12 +08:00
    @Cbdy 这种需求比较多,那这样持久层接口是不是就没有什么用了?
    Miy4mori
        21
    Miy4mori  
       2017-01-11 19:55:25 +08:00 via Android
    spring data jpa 也可以自定义 mapper ,请仔细阅读文档
    incompatible
        22
    incompatible  
       2017-01-11 19:55:48 +08:00
    分两次查询咯

    1. ARepository.findAll(Pagable),从取到的结果中 collect 出 bids
    2. BRespository.find(Iterator of bids),然后手工跟步骤 1 的结果组合起来。

    还有,从你的场景看来, b 可能是类似“分类”这样的基础数据? 这样的话针对 bid->bname 做一个缓存,步骤 2 的中直接查缓存,性能会更好。
    Weixk
        23
    Weixk  
       2017-01-11 20:07:01 +08:00
    @Cbdy 觉得原生的 EntityManager 太粗糙了,还不如使用 JdbcTemplate 。
    srx1982
        24
    srx1982  
       2017-01-11 20:09:16 +08:00
    @palmers 有异常的话,可以贴出来看看
    BruceLi
        25
    BruceLi  
       2017-01-11 20:28:56 +08:00
    google 一下 jpa namednativequery resultsetmapping 就能找到答案了。
    sdandroid
        26
    sdandroid  
       2017-01-12 09:46:24 +08:00
    @palmers 把查询 sql 做成视图,在创建和视图对应的 domain ,这样就是单表操作
    palmers
        27
    palmers  
    OP
       2017-01-12 10:20:49 +08:00
    @sdandroid 但是这个是变化的,而且很多啊 这个没完没了了就
    palmers
        28
    palmers  
    OP
       2017-01-12 10:21:48 +08:00
    @BruceLi 我没有找到使用 jpa 分页然后还可以自定义返回对象的 解答
    palmers
        29
    palmers  
    OP
       2017-01-12 10:33:01 +08:00
    @Miy4mori 你是指在实体类上定义 resultmapper 吗?
    Miy4mori
        30
    Miy4mori  
       2017-01-12 12:20:35 +08:00 via Android
    @palmers 是的 另外 spring data jpa reference 里就有 native 查询加分页的例子
    teemoer
        31
    teemoer  
       2017-01-12 13:09:31 +08:00
    返回 @query 注解下面的 方法 返回 类型 定义为

    list<你定义的临时类> findByQueryAnnon();

    下面是你临时类的定义
    class 临时类{

    ax ;
    cd ;
    ax;

    // 三个字段 生成 get set 方法 我就是这样处理的
    }
    palmers
        32
    palmers  
    OP
       2017-01-12 13:29:25 +08:00
    @teemoer 那你 @query 内容 sql 语句是什么样的?
    palmers
        33
    palmers  
    OP
       2017-01-12 13:35:39 +08:00
    @Miy4mori 我尝试了,但是报错, 一直提示 No property guessView found for type socgu!
    @SqlResultSetMapping(
    name="view",
    classes={
    @ConstructorResult(
    targetClass=TView.class,
    columns={
    @ColumnResult(name = "sumber",type = String.class),

    @ColumnResult(name = "lname",type = String.class),

    @ColumnResult(name = "mnumber",type = String.class),

    @ColumnResult(name = "mtime",type = Date.class),

    @ColumnResult(name = "hname",type = String.class),

    @ColumnResult(name = "vname",type = String.class)
    }
    )
    }
    )

    @NamedNativeQuery(name="getView", query="select sg.sumber as sumber,sl.lname as lname, sg.mnumber as mnumber,sg.mtime as mtime,sg.hname as hname,sg.vname as vname from socgu sg left join soccle sl on sl.cguid = sg.leId", resultSetMapping="view")
    BruceLi
        34
    BruceLi  
       2017-01-12 16:07:43 +08:00
    @palmers query 不是有 setFirstResult(), setMaxResults() 这两个 api 吗。
    palmers
        35
    palmers  
    OP
       2017-01-12 16:31:04 +08:00
    @BruceLi 你好, 能详细说说吗?
    q397064399
        36
    q397064399  
       2017-01-13 10:13:37 +08:00
    Spring in Action EntityManager 注入就好了 然后用 sql 查询,查询完了 之后组装实体
    ebony0319
        37
    ebony0319  
       2019-06-25 23:37:50 +08:00
    老哥,有新的解决方案么。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2650 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 30ms UTC 12:01 PVG 20:01 LAX 04:01 JFK 07:01
    Do have faith in what you're doing.
    ubao msn 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