You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 10:17:23