SpringBoot使用JPA多表关联动态查询指定字段

  • 目标需求
  • Maven依赖
  • 项目结构
  • 代码
  • 运行结果
  • 源码下载

目标需求

在SpringBoot中用JPA实现多表关联动态查询,并且只查询指定字段和返回指定字段
业务对应数据表(关联关系已在图中标出)

某API需要返回的字段

分析:需要进行三表关联一次性查出,JPA转换SQL语句时就限制查询指定字段

Maven依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope>
</dependency>

项目结构


注:按本文写法查询可不需要repository,repository只用来进行save、update、delete操作

代码

application.properties

#对应数据库为Mysql8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://192.168.184.133:3306/jpademo
spring.datasource.username=test
spring.datasource.password=test
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true

实体类及其注解由IDEA自动生成,生成方法见这里,对于生成后的实体类我们仅需加上关联表的相关代码即可。
StorageFile.java(关联了其它2个表)

@Entity
@Table(name = "storage_file")
public class StorageFile {private String fileId;private String fileName;private Integer fileStatus;private Date fileUpdateTime;private String dirId;private String pathId;private StorageDir storageDir; //关联表的实体类 private StoragePath storagePath; //关联表的实体类@ManyToOne // 定义表之间的记录关系,这里为多对一// JoinColumn定义关联字段,name为数据库里的字段名称// insertable和updatable设成false防止重复映射问题@JoinColumn(name = "dir_id", insertable = false, updatable = false)public StorageDir getStorageDir() {return storageDir;}public void setStorageDir(StorageDir storageDir) {this.storageDir = storageDir;}@ManyToOne@JoinColumn(name = "path_id", insertable = false, updatable = false)public StoragePath getStoragePath() {return storagePath;}public void setStoragePath(StoragePath storagePath) {this.storagePath = storagePath;}@Id@Column(name = "file_id")public String getFileId() {return fileId;}public void setFileId(String fileId) {this.fileId = fileId;}@Basic@Column(name = "file_name")public String getFileName() {return fileName;}public void setFileName(String fileName) {this.fileName = fileName;}@Basic@Column(name = "file_status")public Integer getFileStatus() {return fileStatus;}public void setFileStatus(Integer fileStatus) {this.fileStatus = fileStatus;}@Basic@Column(name = "file_update_time")public Date getFileUpdateTime() {return fileUpdateTime;}public void setFileUpdateTime(Date fileUpdateTime) {this.fileUpdateTime = fileUpdateTime;}@Basic@Column(name = "dir_id")public String getDirId() {return dirId;}public void setDirId(String dirId) {this.dirId = dirId;}@Basic@Column(name = "path_id")public String getPathId() {return pathId;}public void setPathId(String pathId) {this.pathId = pathId;}
}

StFileVo.java(封装查询返回的字段)

public class StFileVo {private String fileName;private Date fileUpdateTime;private String dirName;private Integer dirDeep;private Integer pathNode;private String pathValue;// 需要什么字段,就定义什么样的构造函数,一定要有构造函数public StFileVo(String fileName, Date fileUpdateTime, String dirName, Integer dirDeep, Integer pathNode, String pathValue) {this.fileName = fileName;this.fileUpdateTime = fileUpdateTime;this.dirName = dirName;this.dirDeep = dirDeep;this.pathNode = pathNode;this.pathValue = pathValue;}// Getter ... // Setter ...
}

PageCount.java(封装查询返回的分页信息和数据)

public class PageCount<T> {private int page; //当前页private int size; //记录数private long total; //总记录数private List<T> data; //数据public PageCount(int page, int size) {this.page = page;this.size = size;}//获取当前页首条记录下标public int first() {return (page - 1) * size;}//获取当前页末条记录下标public int max() {return page * size;}//构建select count语句public CriteriaQuery<Long> count(CriteriaBuilder criteriaBuilder, Predicate predicate, Class<?> clazz, LinkedHashMap<String,JoinType> joinMap){CriteriaQuery<Long> criteriaQuery = criteriaBuilder.createQuery(Long.class);Root<?> root = criteriaQuery.from(clazz);joinMap.forEach(root::join);return criteriaQuery.select(criteriaBuilder.count(root)).where(predicate);}// Getter ... // Setter ...
}

StorageService.java(JPA动态查询)

@Service
public class StorageService {@PersistenceContextprivate EntityManager entityManager;public PageCount<StFileVo> findStFileVo(PageCount<StFileVo> pageCount, String dirName, Date fileUpdateTime) {CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();// criteriaBuilder.createQuery指定了字段的结果视图CriteriaQuery<StFileVo> criteriaQuery = criteriaBuilder.createQuery(StFileVo.class);// createQuery.from拥有关联信息的实体类(基础表)Root<StorageFile> root = criteriaQuery.from(StorageFile.class);// join关联的实体类,方式为inner joinJoin<Object, Object> join = root.join("storageDir", JoinType.INNER);Join<Object, Object> join1 = root.join("storagePath", JoinType.INNER);Predicate predicate = criteriaBuilder.conjunction();List<Expression<Boolean>> expressions = predicate.getExpressions();// 设定动态查询条件if (fileUpdateTime != null) {expressions.add(criteriaBuilder.equal(root.get("fileUpdateTime"), fileUpdateTime));}if (StringUtils.hasText(dirName)) {expressions.add(criteriaBuilder.equal(join.get("dirName"), dirName));}// select ... from ... where ...criteriaQuery.select(criteriaBuilder.construct(StFileVo.class,root.get("fileName").alias("fileName"), root.get("fileUpdateTime").alias("fileUpdateTime"),join.get("dirName").alias("dirName"), join.get("dirDeep").alias("dirDeep"),join1.get("pathNode").alias("pathNode"), join1.get("pathValue").alias("pathValue"))).where(predicate);// 传入分页参数,查询出需要的记录List<StFileVo> stFileVos = entityManager.createQuery(criteriaQuery).setFirstResult(pageCount.first()).setMaxResults(pageCount.max()).getResultList();pageCount.setData(stFileVos);// 构建joinMap,key和value与root.join的一致LinkedHashMap<String,JoinType> joinMap = new LinkedHashMap<String,JoinType>(){{put("storageDir",JoinType.INNER);put("storagePath",JoinType.INNER);}};// select countLong total = entityManager.createQuery(pageCount.count(criteriaBuilder,predicate,StorageFile.class,joinMap)).getSingleResult();pageCount.setTotal(total);return pageCount;}
}

StorageController.java(请求与响应)

@RestController
@RequestMapping("/test")
public class StorageController {private StorageService storageService;@Autowiredpublic void setStorageService(StorageService storageService) {this.storageService = storageService;}@RequestMapping("/test")public PageCount<StFileVo> test(){return storageService.findStFileVo(new PageCount<>(1,5),"测试目录",null);}
}

运行结果


↑↑↑控制台打印的SQL语句,可以看到select时只查询了API需要的字段

↓↓↓API响应的结果

源码下载

https://github.com/B1ackReimu/jpademo

SpringBoot使用JPA多表关联动态查询指定字段相关推荐

  1. jpa多表联查动态_jpa多表关联动态查询(自定义sql语句)

    项目中,jpa对于简单的数据库操作很方便,但如果多表关联动态查询时,需要自己去写SQL语句拼接查询条件,以下为本人学习的例子. 类似于这种多条件动态查询: 项目用的是springboot 2.1.0. ...

  2. jpa多表关联条件查询实现

    通过实体类映射实现多表关联条件查询 jpa对于多表关联可以在实体类中进行关联映射,一对一用@OneToOne,一对多用@OneToMany,多对多用@ManyToMany,多对一用@ManyToOne ...

  3. Springboot整合JPA 多表关联操作 @Query

    如果还没使用过JPA的可以去先看我这篇:https://blog.csdn.net/qq_35387940/article/details/102541311 这篇文章里我所采取的是使用Map来 替代 ...

  4. jpa多表联查动态_Spring Data JPA实现动态多表关联查询

    在面向关系型数据库(例如:MySQL)的查询中,动态的.多表关联的查询属于比较复杂的情况.所以,我们只要掌握了这种复杂的查询,当面对其他查询情况时,就能做到胸有成竹. 在java工程中,目前我所了解到 ...

  5. jpa多表关联查询_JPA【关联查询篇】

    摘要:本文主要介绍JPA的多表关联查询(一对一.一对多.双向关联.多对一.多对多)以及N+1查询的优化. 1. JPA多表关联查询 多表关联查询就是实现使用一个实体类对象操作或者查询多个表的数据. 配 ...

  6. Spring Data JPA 多表关联查询的实现

    Spring Data JPA 多表关联查询的实现 多表查询在spring data jpa中有两种实现方式,第一种是利用hibernate的级联查询来实现,第二种是创建一个结果集的接口来接收连表查询 ...

  7. oracle两表联查分组,oracle解决多表关联分组查询问题

    做了一个功能需要分组查询,同时查询A表分组查询的ID需要关联B表的数据,本来想两个表关联查询,但是报group by 语法不正确.所以做了以下修改. select count(*), cindexid ...

  8. mybitsPlus QueryWrapper表关联分页查询

    mybitsPlus QueryWrapper表关联分页查询 一. 描述 项目中用到页面查询,并且涉及到两个表分页查询,搜索条件涉及到两个表. 二. 思路 1.Mapper中自定义表关联的SQL,传入 ...

  9. 通过表单设计器动态生成数据库表以及动态查询的功能实现

    表单设计器动态生成数据库表以及动态查询的功能实现 前言 1. 功能实现 1.1 效果说明 1.2 功能流程图 1.3 具体后端实现 1.4 实现效果 2. 尾声 前言 前两天安排了作为Java小码农的 ...

最新文章

  1. Codeforces 460E Roland and Rose(暴力)
  2. AWS — AWS 上的 MEC
  3. python不小心用关键字做了变量名,怎么改回来
  4. Linux下的TCP Wrapper机制
  5. html修改span中的内容,在HTML中抓取span的内容
  6. HDU - 2222 Keywords Search(AC自动机)
  7. STL源码剖析 序列式容器 deque双端队列
  8. 清华硕士一针见血:这些才是机器学习必备的数学基础
  9. hdfs中与file数组类似的数组_EXCEL中数组的应用专题之十二:行列数相同数组的运算...
  10. css 类别选择器 并集,CSS常用选择器
  11. 商品翻牌效果(纯css)
  12. 谷歌了java集成开发_Spring整合Kaptcha谷歌验证码工具的开发步骤
  13. python对平面设计有用吗_平面设计有前途吗?
  14. 基于单片机的智能数字电子秤设计
  15. pytorch训练网络 程序未报错 但是训练不动
  16. 机器学习基石-05-3-Effective Number of Hypotheses
  17. FLy_buck 拓扑结构
  18. jm8.6之参数,函数简介
  19. Linux网卡重命名规则
  20. PMI-ACP练习题(7)

热门文章

  1. 2022年复盘:越走越偏
  2. SHU1923 穿墙术(三维BFS)
  3. C#监控-通过PerformanceCounter实现Process的Cpu占用率以及GC占用监控
  4. Linux频繁自动重启原因排查
  5. 每天一个Linux命令(20):目录结构
  6. 星河战神显示服务器异常,星河战神玩家误区有哪些 玩家常见错误一览
  7. js 对象深复制(深拷贝)
  8. Java中I/O(输入/输出)的操作
  9. 人工智能ai算法_AI算法和联邦贸易委员会
  10. 兄弟3150cdn灯亮error_兄弟2240d打印机drum和error灯同时亮该怎么解决?