如何使用Spring JPA Specification实现按前缀查询关联的国家码数据
JPA Specification 实现关联查询方案
1. 前置依赖:Repository 继承 Specification 执行接口
首先要确保操作PrefixEntity的Repository继承JpaSpecificationExecutor,才能支持Specification查询:
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; public interface PrefixRepository extends JpaRepository<PrefixEntity, Long>, JpaSpecificationExecutor<PrefixEntity> { }
2. 完整Specification实现
按照你预期的结构实现查询逻辑,和你给出的原生SQL效果完全一致:
import org.springframework.data.jpa.domain.Specification; import javax.persistence.criteria.Join; import javax.persistence.criteria.JoinType; // 替换为你自己实体类的包路径 import com.example.entity.PrefixEntity; import com.example.entity.CountryCodeEntity; public interface PrefixSpecification { static Specification<PrefixEntity> joinTest(String targetPrefix) { return (root, query, criteriaBuilder) -> { // 内连接关联国家码表,对应PrefixEntity中的countryCodes属性 Join<PrefixEntity, CountryCodeEntity> countryCodes = root.join("countryCodes", JoinType.INNER); // 匹配prefix字段等于传入值,root.get的属性名要和实体类字段名完全一致 return criteriaBuilder.equal(root.get("prefix"), targetPrefix); }; } // 【可选】如果需要直接返回国家码字符串列表,不需要额外遍历实体,可以用下面这个Specification static Specification<String> getCountryCodeSpec(String targetPrefix) { return (root, query, criteriaBuilder) -> { Join<PrefixEntity, CountryCodeEntity> countryCodes = root.join("countryCodes", JoinType.INNER); // 指定查询返回的字段为countryCode query.select(countryCodes.get("countryCode")); // 可选:去重避免重复返回相同国家码 query.distinct(true); return criteriaBuilder.equal(root.get("prefix"), targetPrefix); }; } }
3. 调用方式
方式1:按你示例的调用逻辑,查询后提取国家码
// 查询匹配前缀的前缀实体列表 List<PrefixEntity> prefixList = prefixRepository.findAll(Specification.where(PrefixSpecification.joinTest("371"))); // 遍历提取所有关联的国家码 List<String> countryCodeList = prefixList.stream() .flatMap(prefix -> prefix.getCountryCodes().stream()) .map(CountryCodeEntity::getCountryCode) .distinct() .toList();
方式2:直接查询返回国家码字符串列表
需要额外定义一个支持字符串返回的Repository:
import org.springframework.data.jpa.repository.JpaSpecificationExecutor; public interface CountryCodeQueryRepository extends JpaSpecificationExecutor<String> { }
调用逻辑更简洁:
List<String> countryCodeList = countryCodeQueryRepository.findAll(PrefixSpecification.getCountryCodeSpec("371"));
注意事项
- Specification中
root.get("xxx")的属性名必须和Java实体类的字段名完全一致,不能使用数据库的下划线命名 - 关联字段名
countryCodes必须和PrefixEntity中定义的OneToMany属性名完全一致,否则会抛出字段不存在异常
内容的提问来源于stack exchange,提问作者makson
相关产品推荐
相关产品推荐

