如何在Spring JPA Specification中实现带子查询的IN子句
实现Spring JPA Specification对应子查询谓词
需求对应SQL
select * from a where xid in (select id from b where name like '%abc%')
其中xid是表a关联表b的外键。
实体类假设
先定义对应的JPA实体类(基础场景):
- 表
a对应的实体A:
@Entity @Table(name = "a") public class A { @Id private Long id; private Long xid; // 关联b表id的外键字段 // 其他字段、getter/setter省略 }
- 表
b对应的实体B:
@Entity @Table(name = "b") public class B { @Id private Long id; private String name; // 其他字段、getter/setter省略 }
Specification实现代码
通过JPA Criteria的Subquery构建子查询,再关联主查询的in条件:
import org.springframework.data.jpa.domain.Specification; import javax.persistence.criteria.*; public class ASpecifications { public static Specification<A> xidInBWithNameLike(String keyword) { return (root, query, criteriaBuilder) -> { // 构建子查询:select id from b where name like '%{keyword}%' Subquery<Long> subquery = query.subquery(Long.class); Root<B> bRoot = subquery.from(B.class); subquery.select(bRoot.get("id")) .where(criteriaBuilder.like(bRoot.get("name"), "%" + keyword + "%")); // 主查询条件:xid 包含在子查询结果中 return criteriaBuilder.in(root.get("xid")).value(subquery); }; } }
关联实体场景适配
如果A实体是通过对象关联B(而非直接存外键值),比如:
@Entity @Table(name = "a") public class A { @Id private Long id; @ManyToOne @JoinColumn(name = "xid") private B b; // 关联B实体 // 其他字段、getter/setter省略 }
对应的Specification可以调整为:
public static Specification<A> bNameLike(String keyword) { return (root, query, criteriaBuilder) -> { Subquery<Long> subquery = query.subquery(Long.class); Root<B> bRoot = subquery.from(B.class); subquery.select(bRoot.get("id")) .where(criteriaBuilder.like(bRoot.get("name"), "%" + keyword + "%")); return criteriaBuilder.in(root.get("b").get("id")).value(subquery); }; }
使用方式
在JpaRepository中直接调用该Specification:
// 假设ARepository继承JpaRepository<A, Long>和JpaSpecificationExecutor<A> List<A> result = aRepository.findAll(ASpecifications.xidInBWithNameLike("abc"));
内容的提问来源于stack exchange,提问作者pappu_kutty
相关产品推荐
相关产品推荐

