V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
palmers
V2EX  ›  Java

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

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

    继承了 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
    @mercurylanded 同意。 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   ·   我们的愿景   ·   实用小工具   ·   5205 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 47ms · UTC 09:27 · PVG 17:27 · LAX 02:27 · JFK 05:27
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.