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

请教一个 jpa 的 Specification 查询问题

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

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

        public Page<OrderEntity> findAllAuto(final String sysno){
            Sort sort = 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   ·   实用小工具   ·   2798 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 11:56 · PVG 19:56 · LAX 03:56 · JFK 06:56
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.