请教一个 jpa 的 Specification 查询问题

2016-12-17 20:12:43 +08:00
 zhengxin1993

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

    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);
    }
7683 次点击
所在节点    Java
12 条回复
Lpl
2016-12-17 20:38:57 +08:00
你这样写太复杂了,你试试 querydsl 。嗯..在外边,回去了补一段代码
MasterMonkey
2016-12-17 21:01:18 +08:00
表示曾经非常迷恋 jpa , 但是从来都没有在项目中实战过!
zhengxin1993
2016-12-17 21:04:10 +08:00
@Lpl 谢谢!
Lpl
2016-12-17 23:10:01 +08:00
@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
2016-12-17 23:19:11 +08:00
q397064399
2016-12-18 06:53:16 +08:00
讲道理 JPA 上手 确实有点繁琐,我不知道公司用的多不多,
如果可以的话,一些复杂的查询,用 Mybatis 配合手动 SQL 比较好,
相对而言, JPA 封装之后,你都不知道怎么改,而且上手非常繁琐, Mybatis 只是解决了数据与 POJO 的绑定,
而查询与结果集优化 却完全交给了用户,
0915240
2016-12-18 11:21:28 +08:00
讲真 jpa 的愿景真的很好 但是总感觉真好以至于被框住🙊
zhengxin1993
2016-12-18 11:38:53 +08:00
@Lpl 非常感谢。
@q397064399 趁着还在学校随便写写,踩踩坑。
@0915240 我觉得语言中能有框的选择还是好的,可以选择被框和不被框。
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
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
2016-12-19 22:28:16 +08:00
@hantsy 在 org.springframework.data.jpa.repository.support 里的 SimpleJpaRepository 的类中,大概第 370 行。包的版本是 1.10.4
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, ...) 就行了。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/328332

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX