请教一个 jpa 的 Specification 查询问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
zhengxin1993
V2EX    Java

请教一个 jpa 的 Specification 查询问题

  •  
  •   zhengxin1993 2016-12-17 20:12:43 +08:00 8277 次点击
    这是一个创建于 3299 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我想查询表中的某些字段,但是我这样子写没有报错,但是把自身表中和关联表中的所有字段都查出来了,如何做到动态查询且只查询表中的某些字段和关联表中的某些字段?

     public Page<OrderEntity> findAllAuto(final String sysno){ Sort srt = new Sort(Sort.Direction.DESC, "orderId"); Pageable pageable = new PageRequest(0,5,sort); return orderRepository.findAll(new Specification<OrderEntity>() { public Predicate toPredicate(Root<OrderEntity> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) { Path<String> sys_no = root.get("sysno"); CompoundSelection<OrderEntity> cSelect = criteriaBuilder.construct(OrderEntity.class, root.get("orderId"), root.get("sysno")); criteriaQuery.multiselect(cSelect); criteriaQuery.where(criteriaBuilder.like(sys_no, sysno)); return null; } }, pageable); } 
    12 条回复    2016-12-19 22:57:36 +08:00
    Lpl
        1
    Lpl  
       2016-12-17 20:38:57 +08:00 via Android
    你这样写太复杂了,你试试 querydsl 。嗯..在外边,回去了补一段代码
    MasterMonkey
        2
    MasterMonkey  
       2016-12-17 21:01:18 +08:00
    表示曾经非常迷恋 jpa , 但是从来都没有在项目中实战过!
    zhengxin1993
        3
    zhengxin1993  
    OP
       2016-12-17 21:04:10 +08:00
    @Lpl 谢谢!
    Lpl
        4
    Lpl  
       2016-12-17 23:10:01 +08:00   2
    @zhengxin1993

    ```
    import javax.persistence.EntityManager;

    public class Test {
    @Autowired
    private EntityManager entityManager;

    public void testQueryDsl(Integer categoryId) {
    JPAQuery query = new JPAQuery(entityManager);

    // QAaaa 是 Querydsl 根据 Aaaa 这个 Bean 生成的一个对象, test1 相当于你使用多表 JOIN 的时候每个表的别名
    // 假定 aaa 是分类, bbb 是文章
    QAaaa qAaaa = new QAaaa("test1");
    QBbbb qBbbb = new QBbbb("test2");

    JPAQuery result = query.from(qAaaa, qBbbb)
    .where(
    qAaaa.categoryId.eq(qBbbb.id),
    qAaaa.id.eq(categoryId),
    qBbbb.categoryId.eq(categoryId)
    ).orderBy(qAaaa.createTime.desc());

    // 关键点来了, 我们查找出来的数据, 每行都包含了 aaa 和 bbb 字段,
    // 那么, 我们 list 的时候只 list 了 aaa
    List<Aaaa> aaaaList = result.list(qAaaa);
    }
    }
    ```

    JPA 底层用的是 Hibernate 的实现, JAR :
    hibernate-jpa-xxx-api

    JPAQuery 是 Querydsl 关于 JPA 接口的实现:
    ```
    JPAQuery is the default implementation of the JPQLQuery interface for JPA
    ```

    QAaaa/QBbbb 是 Querydsl 根据你的 JavaBean 生成的类:
    ```
    QAaaa is a Querydsl query type for Aaaa
    ```

    大概是这些。。说的不怎么清楚,你再看看 Querydsl 文档:
    https://github.com/querydsl/querydsl
    Lpl
        5
    Lpl  
       2016-12-17 23:19:11 +08:00
    q397064399
        6
    q397064399  
       2016-12-18 06:53:16 +08:00
    讲道理 JPA 上手 确实有点繁琐,我不知道公司用的多不多,
    如果可以的话,一些复杂的查询,用 Mybatis 配合手动 SQL 比较好,
    相对而言, JPA 封装之后,你都不知道怎么改,而且上手非常繁琐, Mybatis 只是解决了数据与 POJO 的绑定,
    而查询与结果集优化 却完全交给了用户,
    0915240
        7
    0915240  
       2016-12-18 11:21:28 +08:00 via iPhone
    讲真 jpa 的愿景真的很好 但是总感觉真好以至于被框住
    zhengxin1993
        8
    zhengxin1993  
    OP
       2016-12-18 11:38:53 +08:00 via Android
    @Lpl 非常感谢。
    @q397064399 趁着还在学校随便写写,踩踩坑。
    @0915240 我觉得语言中能有框的选择还是好的,可以选择被框和不被框。
    hantsy
        9
    hantsy  
       2016-12-19 12:13:12 +08:00
    这只是 Spring Data JPA 扩展中的 Specification 。

    某些关联,某些字段,和这个 API 一点关系。

    参考我的例子:

    https://github.com/hantsy/angularjs-springmvc-sample/blob/master/src/main/java/com/hantsylabs/restexample/springmvc/repository/PostSpecifications.java

    参考, 包括 Spring Data JPA 中 Specficcation 和 QueryDSL ( JPA )的例子。 @Lpl Spring Data JPA 包含对 QueryDSL 扩展。

    https://github.com/hantsy/spring4-sandbox/tree/master/data-jpa/src/main/java/com/hantsylabs/example/spring/jpa/spec

    @zhengxin1993 说实话,先去看看 JPA 吧。
    zhengxin1993
        10
    zhengxin1993  
    OP
       2016-12-19 22:24:03 +08:00
    @hantsy 谢谢,你的例子里面并没有取表中某些字段的方法,虽然没能很好的解决,我找到了原因,框架中下面这段代码才使得 toPredicate 方法无法只取某些字段字段。
    ```
    protected <S extends T> TypedQuery<S> getQuery(Specification<S> spec, Class<S> domainClass, Sort sort) {
    CriteriaBuilder builder = this.em.getCriteriaBuilder();
    CriteriaQuery query = builder.createQuery(domainClass);
    Root root = this.applySpecificationToCriteria(spec, domainClass, query);
    query.select(root);
    ```
    框架中实现 findAll 方法中调用了此方法,它又 query.select(root),把所有字段都加回进去了,才导致重写的方法中的 select()无效。
    虽然我是菜鸟,我也不是一有问题就上来问。
    zhengxin1993
        11
    zhengxin1993  
    OP
       2016-12-19 22:28:16 +08:00
    @hantsy 在 org.springframework.data.jpa.repository.support 里的 SimpleJpaRepository 的类中,大概第 370 行。包的版本是 1.10.4
    hantsy
        12
    hantsy  
       2016-12-19 22:57:36 +08:00
    @zhengxin1993 呵呵,。。好像不是很难。

    http://stackoverflow.com/questions/18300465/spring-data-jpa-and-querydsl-to-fetch-subset-of-columns-using-bean-constructor-p

    如果你不在乎 Typesafe ,直接用 JPQL , select new ObjectXXXX(field1, field2, ...) 就行了。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2309 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 33ms UTC 15:53 PVG 23:53 LAX 07:53 JFK 10:53
    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