前言
在适应工作需要的过程中,我从Mybatis Plus转向使用JPA。尽管JPA Criteria API具备类似Mybatis Plus的查询条件构建功能,并且还提供了更多的API,但在实际开发中,很多情况下我们需要处理单表的动态条件查询。然而,JPA Criteria API的书写方式在实现动态查询时显得不够优雅,与Mybatis Plus的Wrapper相比缺乏灵活性。为了提升其使用体验,我进行了对JPA Criteria API的二次封装和扩展,使其能够类似于Mybatis Plus Wrapper的功能。这样一来,开发者在Mybatis Plus与JPA之间切换时能够更加无缝,同时还可以进行更多扩展,例如数据类型转换和共性问题处理。
示例代码
原始JPA Criteria API写法
List<QaCheckTask> all = qaCheckTaskDao.findAll((root, query, cb) -> {
List<Predicate> predicates = new ArrayList<>();
if (taskTypeCode != null) {
predicates.add(cb.equal(root.get("taskTypeCode"), taskTypeCode));
}
if (checkedStartDate != null && checkedEndDate != null) {
predicates.add(cb.between(root.get("checkedDate"), checkedStartDate, checkedEndDate));
}
return cb.and(predicates.toArray(new Predicate[0]));
});
使用Wrapper进行封装的写法
List<QaCheckTask> all = qaCheckTaskDao.findAll(new QueryWrapper<QaCheckTask>()
.eq(taskTypeCode != null, "taskTypeCode", taskTypeCode)
.between(checkedStartDate != null && checkedEndDate != null,
"checkedDate", checkedStartDate, checkedEndDate));
通过我的二次封装,条件构造器的使用更加方便,只需传入相关参数即可。
环境搭建
- 引入依赖(可以直接源代码引入,或以Jar包方式引入)。
- 在启动类上添加 @EnableJpaRepositories(repositoryFactoryBeanClass = BaseRepositoryFactory.class)。
- Repositories/Dao层继承 extends BaseRepository<查询的实体对象, 主键类型>。
注意事项
-
JPA是面向对象的,若只是指定查询字段,您还需要在实体中添加与查询字段一一对应的构造方法,以便JPA能够正常将结果映射至对象中。
-
本Wrapper在时间有限的情况下进行了封装,可能无法满足所有需求。若有兴趣,您可以自行扩展。
-
尽管我提供了许多便利的API,但有些扩展API可能只适用于特定数据库(例如Oracle)。
-
该Wrapper可能会对项目产生一定的影响,若不想修改其他内容,只使用QueryWrapper,您可以在Repository接口中继承JpaSpecificationExecutor类,并使用
.build()
方法来获取条件,不过部分功能(如select)可能会失效。 -
如果是第一次使用JPA的话,可能并不知道JPA的自动更新,JPA查询的结果默认为托管状态,但托管状态下的对象被更新,则会自动更新至数据库,解决方案也很简单如下:
@PersistenceContext private EntityManager entityManager; // 将对象设置为游离状态 // 这样对游离状态下的对象进行set就不会触发自动更新了 entityManager.detach(Object)
-
如果有任何问题,欢迎指正或提供更好的解决方案,我的经验仍然有限,期待您的建议。
结语
通过对JPA Criteria API的增强,我实现了类似Mybatis Plus Wrapper的功能,使开发者能够在使用JPA时也享受更加灵活、高效的条件构造器。我希望这个封装能够让您更专注于业务逻辑,提升开发效率。如果有不足之处,欢迎各位读者不吝赐教。您的建议将有助于改进和完善。