JPA的多表复杂查询

最近工作中由于要求只能用hibernate+jpa 与数据库进行交互,在简单查询中,jpa继承CrudRepository<T, ID>接口 ,然后利用jpa的方法命名规范进行jpql查询,然而在进行复杂查询时,需要继承JpaSpecificationExecutor接口 利用Specification 进行复杂查询,由于我自己就遇到了这一问题,查了好多资料,虽然有方法,但是都没有一个详细的讲解,以至于知道方法而不能很好的利用jpa复杂查询的方便之处。我将举几个栗子,来详细的说一下我自己在使用jpa多表复杂查询的场景和想法。

栗子1:

以一个实体类User中的几个属性进行筛选。

1. 名字
2. ID
3. 手机号

这是一个单表的多条件复杂查询,由于是在几个属性中进行筛选,其中的属性的个数不知道有多少个,所以只需要利用Specification 查询就可以很方便的实现这个需求。 下面请看代码:
场景:页面上通过条件筛选,查询用户列表

这里有3个条件 在页面上我设置的id分别为searchName,searchId,searchMobile。 由于这个是user表 所以userRepository 继承JpaSpecificationExecutor接口,随后我创建了一个封装条件的类

public class PageParam<T> {
private Integer pageSize = 10;
private Integer pageNumber = 1;
private String searchName;
private String searchMobile;
private String searchId;
}

由于我这个方法是直接分页的 所以pageNumber 和pageSize 也可以直接写入到这个类中,用于方便接收参数,主要是对下面3个参数的封装

Specification<T> specification = new Specification<T>() {

@Override
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
List<Predicate> list = new ArrayList<Predicate>();

if (StringUtils.isNotBlank(searchName)) {
list.add(cb.like(root.get("name").as(String.class), "%" + searchName + "%"));
}

if (StringUtils.isNotBlank(searchId)) {
list.add(cb.equal(root.get("id").as(Long.class), searchId));
}

if (StringUtils.isNotBlank(searchMobile)) {
list.add(cb.like(root.get("mobile").as(String.class), "%" + searchMobile + "%"));
}

Predicate[] p = new Predicate[list.size()];
return cb.and(list.toArray(p));
};
};

这里因为都是一个表,所以只要root.get(‘N ‘)这个N对应所要查的 属性的名字就好,属性名 属性名 重要的事情说三遍。
再接下来看一组多表的查询

栗子2:

这里有4张表

public class Living {
Long id;

@ManyToOne
@JsonIgnore
@JoinColumn(name = "actorId", foreignKey = @ForeignKey(name = "none", value =ConstraintMode.NO_CONSTRAINT))
public Actor actor;

@ManyToOne
@JsonIgnore
@JoinColumn(name = "regionId", foreignKey = @ForeignKey(name = "none", value =ConstraintMode.NO_CONSTRAINT))
public Region region;
}
public class Actor {
Long id;

@OneToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH }, fetch = FetchType.LAZY)
@JoinColumn(name = "actorId")
@org.hibernate.annotations.ForeignKey(name = "none")
List<Living> livings = new ArrayList<>();

@OneToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH }, fetch = FetchType.LAZY)
@org.hibernate.annotations.ForeignKey(name = "none")
@JoinColumn(name = "userDetailId", foreignKey = @ForeignKey(name = "none", value = ConstraintMode.NO_CONSTRAINT))
UserDetail userDetail;

@Column(nullable = false)
@Enumerated(value = EnumType.ORDINAL)
ActorType actorType = ActorType.A;

public enum ActorType{
A,B,C
}
}
public class UserDetail {
Long id;

@OneToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH }, fetch = FetchType.LAZY)
@org.hibernate.annotations.ForeignKey(name = "none")
@JoinColumn(name = "actorId", foreignKey = @ForeignKey(name = "none", value = ConstraintMode.NO_CONSTRAINT))
Actor actor;

String truename;
}
public class Region {
Long id;

String name;

@OneToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH }, fetch = FetchType.LAZY)
@JoinColumn(name = "regionId")
@org.hibernate.annotations.ForeignKey(name = "none")
List<Living> Livings;
}

现在要根据userdetai 种的 sex actor中的actortype 还有 region的id 为条件查询出满足条件的living。

public class PageParam<Living> {
private Integer pageSize = 10;
private Integer pageNumber = 1;
private Sex sex;
private ActorType actortype;
private Long cityid;

首先我还是封装了这样一个类,但是这里的泛型 我是直接给到了想要的查询结果的泛型,接下来 因为这里涉及到了一个 多表的查询 所以上面的单表查询的例子 已经不适合这个查询了,但是Criteria 的join方法 给我们提供了一个模式

Specification<Living> specification = new Specification<Living>() {

@Override
public Predicate toPredicate(Root<Living> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
List<Predicate> list = new ArrayList<Predicate>();

if (null!=sex) {
Join<UserDetail, Living> join = root.join("actor", JoinType.LEFT);
list.add(cb.equal(join.get("userDetail").get("sex"), sex ));
}

if (null!=actortype) {
Join<Actor, Living> join = root.join("actor", JoinType.LEFT);
list.add(cb.equal(join.get("actorType"), actortype));
}
if (null!=cityid) {
Join<Region, Living> join = root.join("region", JoinType.LEFT);
list.add(cb.equal(join.get("id"), cityid));
}

//Join<A, B> join = root.join("bs", JoinType.LEFT);
//list.add(cb.equal(join.get("c").get("id"), id));
Predicate[] p = new Predicate[list.size()];
return cb.and(list.toArray(p));
};
};

这里是我对条件进行的封装。jpa 的多条件查询 主要是根据Criteria 为我们提供的方法封装条件,然后根据 给条件定义的位置,再生成sql语句,之后完成查询。
不得不说的地方,在这个多表的查询中以下面这句为例

Join<UserDetail, Living> join = root.join("actor", JoinType.LEFT);
list.add(cb.equal(join.get("userDetail").get("sex"), sex ));

jointype.LEFT主要是说最终的这个属性 是在哪个表中, 而前面的 “actor” 则表示 从living表中 查询的 第一步的查询,比如我给出的例子 是要查询出 living 中的 actor 然后是actor 中的userdetail 之后才是 userdetail中的 sex属性 所以下面的join.get(“userDetail”).get(“sex”) ,这里就是get出相应的属性,一直到你得到想要的属性为止。 接下来的两个属性 也同理,
许多人多jpa 有很大的误解,认为jpa 的多表,多条件复杂查询,不如mybatis的查询,在之前我也是这么觉得,但自从通过jpa 实现了这个多表多条件的复杂查询之后,我觉得hibernate的复杂查询 不逊于mybatis ,尤其是对sql 语句不是很精通的 码农,虽然hibernate的门槛较高可jpa 恰恰降低了hibernate 所需要的门槛,希望大家可以通过我的经验,更方便的与数据库进行交互。


money.jpg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/477297.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode 1352. 最后 K 个数的乘积

1. 题目 请你实现一个「数字乘积类」ProductOfNumbers&#xff0c;要求支持下述两种方法&#xff1a; add(int num) – 将数字 num 添加到当前数字列表的最后面。getProduct(int k) – 返回当前数字列表中&#xff0c;最后 k 个数字的乘积。 – 你可以假设当前列表中始终 至少…

颠覆认知!数据增强、正则化可导致不易察觉的灾难?

文 | 子龙编 | 智商掉了一地作为常用的炼丹技巧&#xff0c;正则化 (Regularization) 和数据增强 (Data Augmentation, DA) 常常被简单粗暴地引入模型中来防止数据过拟合&#xff0c;进而提升最后的 performance。如果说&#xff0c;更高的performance就意味着更好的泛化能力&a…

spring-boot-starter-swagger 1.3.0.RELEASE:新增对JSR-303的支持和host的配置

简介 该项目主要利用Spring Boot的自动化配置特性来实现快速的将swagger2引入spring boot应用来生成API文档&#xff0c;简化原生使用swagger2的整合代码。 源码地址 GitHub&#xff1a;https://github.com/dyc87112/spring-boot-starter-swagger码云&#xff1a;https://git…

LeetCode 1353. 最多可以参加的会议数目(排序+贪心,优先队列,难)

文章目录1. 题目2. 解题2.1 错误解2.2 超时解2.3 通过解2.4 大佬解1. 题目 给你一个数组 events&#xff0c;其中 events[i] [startDayi, endDayi] &#xff0c;表示会议 i 开始于 startDayi &#xff0c;结束于 endDayi 。 你可以在满足 startDayi < d < endDayi 中的…

深圳率先立法:支持L3自动驾驶上路,凡公开道路皆可行

文 | 万博 发自 副驾寺源 | 智能车参考全国第一个开放L3级自动驾驶的城市&#xff0c;就要来了。不是自动驾驶第一城的广州&#xff0c;也不是拥有全球首个高级别自动驾驶示范区的北京&#xff0c;最先吃螃蟹的&#xff0c;是深圳。根据深圳人大常委会发布的2022年立法计划&…

在Pivotal Web Service上发布Spring Boot应用

Hello PWS&#xff08;Pivotal Web Service&#xff09;&#xff0c;由 Pivotal 公司提供的 &#xff0c;可以运行Java, Grails, Play, Spring, Node.js, Ruby on Rails, Sinatra or Go 等Web应用的服务。本文将介绍一个 Hello World 级别的 Spring Boot 应用发布到 PWS 的过程…

CVPR 2022 | FAIR提出MaskFeat:自监督视觉预训练新方法!灵感之一来自16年前CVPR论文...

编 | 小咸鱼 好困源 | 新智元【导读】近日&#xff0c;北大校友、约翰霍普金斯大学博士生提出了一种新的方法&#xff1a;MaskFeat&#xff0c;摘下12个SOTA&#xff01;这是一个能用于视频模型的自监督预训练方法&#xff1a;掩码特征预测&#xff08;MaskFeat&#xff09;。论…

简化Swagger使用的自制Starter:spring-boot-starter-swagger,欢迎使用和吐槽

项目简介 该项目主要利用Spring Boot的自动化配置特性来实现快速的将swagger2引入spring boot应用来生成API文档&#xff0c;简化原生使用swagger2的整合代码。 GitHub&#xff1a;https://github.com/dyc87112/spring-boot-starter-swagger码云&#xff1a;http://git.oschi…

LeetCode 1354. 多次求和构造目标数组(优先队列+逆向思考)

1. 题目 给你一个整数数组 target 。一开始&#xff0c;你有一个数组 A &#xff0c;它的所有元素均为 1 &#xff0c;你可以执行以下操作&#xff1a; 令 x 为你数组里所有元素的和选择满足 0 < i < target.size 的任意下标 i &#xff0c;并让 A 数组里下标为 i 处的…

Spring Boot自动化配置的利弊及解决之道

Spring Boot中的双刃剑&#xff1a;自动化配置 在之前发布的Spring Boot基础教程系列文章中&#xff0c;我们通过各种功能性示例体验了Spring Boot的自动化配置给我们所带来的超便利的新开发方式。但是&#xff0c;在一些情况下Spring Boot的自动化配置也会给我们惹来不少的麻…

人在ACL2022,无人戴口罩我有些慌

文 | 小伟大家好&#xff0c;我是阿伟 (不是杰哥不要的阿伟)&#xff0c;NLP小萌新&#xff0c;好久不见&#xff01;之前忙着赶ddl一直没时间写文&#xff0c;趁着这次去都柏林参加了人生第一次线下ACL会议的机会&#xff0c;把自己的一些体验分享给大家。22号早上到了都柏林发…

剑指Offer - 面试题32 - I. 从上到下打印二叉树(按层BFS遍历,queue)

1. 题目 从上到下打印出二叉树的每个节点&#xff0c;同一层的节点按照从左到右的顺序打印。 例如: 给定二叉树: [3,9,20,null,null,15,7],3/ \9 20/ \15 7 返回&#xff1a; [3,9,20,15,7]提示&#xff1a; 节点总数 < 1000来源&#xff1a;力扣&#xff08;LeetCode…

Spring Boot中使用Actuator的/info端点输出Git版本信息

对于Spring Boot的Actuator模块相信大家已经不陌生了&#xff0c;尤其对于其中的/health、/metrics等强大端点已经不陌生&#xff08;如您还不了解Actuator模块&#xff0c;建议先阅读《Spring Boot Actuator监控端点小结》&#xff09;。但是&#xff0c;其中还有一个比较特殊…

管培生走下神坛,“高管捷径”破灭

文 | 翟元元源 | Tech星球曾经令打工人羡慕不已的管培生光环&#xff0c;正逐渐失色。近日&#xff0c;一位叮咚买菜的管培生在某社交平台爆料&#xff0c;管培生这一带有职业光环的角色有着不为人知的B面。“叮咚买菜管培生&#xff0c;别去&#xff0c;快跑。每天12小时以上体…

剑指Offer - 面试题32 - III. 从上到下打印二叉树 III(BFS,queue+stack)

1. 题目 请实现一个函数按照之字形顺序打印二叉树&#xff0c; 即第一行按照从左到右的顺序打印&#xff0c; 第二层按照从右到左的顺序打印&#xff0c; 第三行再按照从左到右的顺序打印&#xff0c;其他行以此类推。 例如: 给定二叉树: [3,9,20,null,null,15,7],3/ \9 20/…

互联网行业,回暖了?

源 | 36氪经过这一年的调整&#xff0c;中国互联网企业或许才算得上真正成熟起来。有统计显示&#xff0c;目前中国互联网公司股价已经缓慢升至 3 个月以来的新高。反映中概股表现的纳斯达克中国金龙指数在近期连涨三天&#xff0c;自5月11日以来更是累计上涨逾40%。利好的信号…

使用Spring Boot Actuator、Jolokia和Grafana实现准实时监控

由于最近在做监控方面的工作&#xff0c;因此也读了不少相关的经验分享。其中有这样一篇文章总结了一些基于Spring Boot的监控方案&#xff0c;因此翻译了一下&#xff0c;希望可以对大家有所帮助。 原文&#xff1a;Near real-time monitoring charts with Spring Boot Actuat…

剑指Offer - 面试题33. 二叉搜索树的后序遍历序列(递归)

1. 题目 输入一个整数数组&#xff0c;判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true&#xff0c;否则返回 false。假设输入的数组的任意两个数字都互不相同。 参考以下这颗二叉搜索树&#xff1a;5/ \2 6/ \1 3 示例 1&#xff1a; 输入: [1,6,3,2,5]…

Geoffrey Hinton 最新访谈:不出五年,我们就会破解大脑的运作机制,但不是通过反向传播...

文 | Geoffrey Hinton整理 | 李梅、黄楠编 | 陈彩娴过去十年&#xff0c;AI 在计算机视觉、语音识别、机器翻译、机器人、医学、计算生物学、蛋白质折叠预测等等领域取得了一个又一个突破&#xff0c;而这些突破的背后&#xff0c;均离不开深度学习。那么&#xff0c;深度学习起…

Spring Boot 1.5.x新特性:动态修改日志级别

前天Spring Boot 1.5终于迎来了第一个RELEASE版本&#xff1a;1.5.0&#xff0c;但是由于一个编译依赖问题在第二天直接连击到了1.5.1。该版本的发布包含了超过320位贡献者的奉献、10000多次的代码提交。 每次Spring Boot版本更新所带来的新特性都是我们每个用户特别关注的。虽…