使用jpa的一些困扰
- 一对多,多对一,多对多的关系要不要建立?
- 返回类型Object[]数组,至于每一个下标对应哪个字段,没法直观的看到,例如object[11]是什么类型?字段名是什么?这个就无法直观得知.
- jpql/native sql中复杂的关系导致不可维护,每一个接手的人都要研究sql半天
- 该种动态拼接条件方法导致类似的代码会大量重复,所以IDEA打开的时候黄了半边天
- 该查询为分页查询,这样写的话,还要再copy一个count查询才能拿到总数,无疑又是代码重复
- JPA这种框架目的就是少些原生sql语句,大量这样的操作的话,还不如使用dbUtil这样的工具类查询
QueryDsl简介
QueryDSL仅仅是一个通用的查询框架,专注于通过Java API构建类型安全的SQL查询。
Querydsl可以通过一组通用的查询API为用户构建出适合不同类型ORM框架或者是SQL的查询语句,也就是说QueryDSL是基于各种ORM框架以及SQL之上的一个通用的查询框架。
借助QueryDSL可以在任何支持的ORM框架或者SQL平台上以一种通用的API方式来构建查询。目前QueryDSL支持的平台包括JPA,JDO,SQL,Java Collections,RDF,Lucene,Hibernate Search。
官网地址 : 点击进入
配置到项目
pom.xml 引入依赖 加入插件,用于生成查询实例Q类
<dependencies>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
</dependency>
</dependencies>
<plugins>
<plugin> <!--因为QueryDsl是类型安全的,所以还需要加上Maven APT plugin,使用 APT 自动生成Q类:-->
<groupId>com.mysema.maven</groupId>
<artifactId>apt-maven-plugin</artifactId>
<version>1.1.3</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>process</goal>
</goals>
<configuration>
<outputDirectory>target/generated-sources/java</outputDirectory>
<processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
实体Bean配置了@Entity被检测到之后,就会在target的子目录中自动生成一个Q+实体名称的类,这个类对我们使用QueryDSL非常重要,正是因为它,我们才使得QueryDSL能够构建类型安全的查询。
修改代码
- 在启动类中添加如下代码
/**
* 让Spring管理JPAQueryFactory
*/
@Bean
public JPAQueryFactory jpaQueryFactory(EntityManager entityManager){
return new JPAQueryFactory(entityManager);
}
- 修改Repository类
@Repository
public interface CustomerRepository extends JpaRepository<Customer, String>, QuerydslPredicateExecutor<Customer>
QueryDsl大于等于,小于等于
大于等于 :goe,小于等于:loe
predicate = StringUtils.isEmpty(param.getParam().get("start")) ? predicate : ExpressionUtils.and(predicate, qMonthcheckplan.start.goe(DateUtils.str2day(param.getParam().get("start").toString())));
predicate = StringUtils.isEmpty(param.getParam().get("end")) ? predicate : ExpressionUtils.and(predicate, qMonthcheckplan.end.loe(DateUtils.str2day(param.getParam().get("end").toString())));
查询并分页
- 简单分页
Pageable pageable = PageRequest.of(query.getPage() - 1, query.getSize());
Predicate predicate = customer.isNotNull().or(customer.isNull());
predicate = query.getBirthdayBegin() == null ? predicate : ExpressionUtils.and(predicate, customer.birthday.goe(query.getBirthdayBegin()));
predicate = query.getBirthdayEnd() == null ? predicate : ExpressionUtils.and(predicate, customer.birthday.loe(query.getBirthdayEnd()));
Page<Customer> pageData = customerRepository.findAll(predicate, pageable);
List<CustomerVO> customers = new ArrayList<>();
pageData.getContent().forEach(x -> {
CustomerVO customerVO = CustomerVO.builder().build();
BeanUtils.copyProperties(x, customerVO);
customers.add(customerVO);
});
return Result.ok(customers, pageData.getTotalElements());
- 条件分页
QCustomer QCustomerOrder:是编译出来的实体
jpaQuery :根据条件查询出来的集合
customers :根据前台传来的进行分页操作
.fetch():相当于.get() 可看出返回类型
QCustomer customer = QCustomer.customer;
QCustomerOrder order = QCustomerOrder.customerOrder;
Pageable pageable = PageRequest.of(query.getPage() - 1, query.getSize());
//组合搜索客户的条件,初始化组装条件(类似where 1=1)
Predicate predicate = customer.isNotNull().or(customer.isNull());
predicate = StrUtil.isBlank(query.getCustomerName()) ? predicate : ExpressionUtils.and(predicate, customer.name.like(FnaUtils.parseLike(query.getCustomerName())));
predicate = StrUtil.isBlank(query.getGender()) ? predicate : ExpressionUtils.and(predicate, customer.gender.eq(query.getGender()));
predicate = query.getBirthdayBegin() == null ? predicate : ExpressionUtils.and(predicate, customer.birthday.goe(query.getBirthdayBegin()));
predicate = query.getBirthdayEnd() == null ? predicate : ExpressionUtils.and(predicate, customer.birthday.loe(query.getBirthdayEnd()));
predicate = StrUtil.isBlank(query.getIdType()) ? predicate : ExpressionUtils.and(predicate, customer.idType.eq(query.getIdType()));
predicate = StrUtil.isBlank(query.getIdNo()) ? predicate : ExpressionUtils.and(predicate, customer.idNo.like(FnaUtils.parseLike(query.getIdNo())));
//组合搜索客户订单的条件,初始化组装条件(类似where 1=1)
Predicate predicate2 = order.isNotNull().or(order.isNull());
predicate2 = StrUtil.isBlank(query.getOrderNo()) ? predicate2 : ExpressionUtils.and(predicate2, order.orderNo.like(FnaUtils.parseLike(query.getOrderNo())));
predicate2 = StrUtil.isBlank(query.getAddress()) ? predicate2 : ExpressionUtils.and(predicate2, order.address.like(FnaUtils.parseLike(query.getAddress())));
JPAQuery<Customer> jpaQuery = jpaQueryFactory.selectFrom(customer).where(predicate);
if (StrUtil.isNotBlank(query.getOrderNo()) || StrUtil.isNotBlank(query.getAddress())) {
jpaQuery.where(customer.customerId.in(
jpaQueryFactory.select(order.customerId).from(order).where(predicate2))
);
}
List<CustomerVO> customers = jpaQuery.offset(pageable.getOffset()).limit(pageable.getPageSize()).fetch().stream().map(x -> {
CustomerVO customerVO = CustomerVO.builder().build();
BeanUtils.copyProperties(x, customerVO);
return customerVO;
}).collect(Collectors.toList());
long count = jpaQuery.fetchCount();
return Result.ok(customers, count);
网友评论