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

Spring Boot JPA @OneToMany关联查询:如何在搜索中包含Product列表

解决JPQL关联实体ProductList的关键词搜索问题

首先先明确实体关联结构(基于你的描述补充常规字段示例):

@Entity
public class Formula {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String description;
    private LocalDateTime time;

    @OneToMany(mappedBy = "formula", fetch = FetchType.LAZY)
    private List<Product> productList;
    // getter/setter 省略
}

@Entity
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String productName; // 假设Product需搜索的字段
    private String productCode; // 假设Product需搜索的字段

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "formula_id")
    private Formula formula;
    // getter/setter 省略
}

下面提供三种修改方案,根据你的场景选择:

1. 直接修改JPQL查询语句

这是最直接的方式,通过LEFT JOIN关联Product实体,将其字段加入搜索条件,并通过DISTINCT避免重复结果:

@Query("SELECT DISTINCT f FROM Formula f LEFT JOIN f.productList p " +
       "WHERE f.name LIKE %:keyword% " +
       "OR f.description LIKE %:keyword% " +
       "OR FUNCTION('DATE_FORMAT', f.time, '%Y-%m-%d %H:%i:%s') LIKE %:keyword% " +
       "OR p.productName LIKE %:keyword% " +
       "OR p.productCode LIKE %:keyword%")
List<Formula> findFormulaBy(@Param("keyword") String keyword);
  • LEFT JOIN:保证即使没有关联Product的Formula也能被搜索到(如果用INNER JOIN会过滤掉无Product的Formula)
  • DISTINCT:避免因关联多个Product导致同一Formula重复返回
  • 日期字段处理:FUNCTION('DATE_FORMAT', ...)是MySQL的日期格式化方式,其他数据库需调整(比如H2用TO_CHAR)

2. 使用Spring Data JPA方法名推导

适合简单场景,无需手写JPQL,但字段过多时方法名会过长:

List<Formula> findDistinctByNameContainingOrDescriptionContainingOrTimeContainingOrProductList_ProductNameContainingOrProductList_ProductCodeContaining(String keyword);

3. 使用Specification/Criteria API(复杂场景推荐)

如果后续需要扩展搜索条件,这种方式更灵活:
首先编写Specification工具类:

public class FormulaSpecifications {
    public static Specification<Formula> searchByKeyword(String keyword) {
        return (root, query, criteriaBuilder) -> {
            // 左关联Product实体
            Join<Formula, Product> productJoin = root.join("productList", JoinType.LEFT);
            
            // 构建各字段的搜索条件
            Predicate formulaName = criteriaBuilder.like(root.get("name"), "%" + keyword + "%");
            Predicate formulaDesc = criteriaBuilder.like(root.get("description"), "%" + keyword + "%");
            Predicate formulaTime = criteriaBuilder.like(
                criteriaBuilder.function("DATE_FORMAT", String.class, root.get("time"), criteriaBuilder.literal("%Y-%m-%d %H:%i:%s")),
                "%" + keyword + "%"
            );
            Predicate productName = criteriaBuilder.like(productJoin.get("productName"), "%" + keyword + "%");
            Predicate productCode = criteriaBuilder.like(productJoin.get("productCode"), "%" + keyword + "%");
            
            // 组合条件并去重
            query.distinct(true);
            return criteriaBuilder.or(formulaName, formulaDesc, formulaTime, productName, productCode);
        };
    }
}

然后让Repository继承JpaSpecificationExecutor:

public interface FormulaRepository extends JpaRepository<Formula, Long>, JpaSpecificationExecutor<Formula> {
}

调用时:

List<Formula> formulas = formulaRepository.findAll(FormulaSpecifications.searchByKeyword(keyword));

注意事项

  • 若查询后需要访问productList,可在JPQL中改用LEFT JOIN FETCH(需保留DISTINCT),避免懒加载异常
  • 请根据你的Product实体实际字段名替换示例中的productName、productCode
  • 日期格式化函数需匹配你使用的数据库类型

内容的提问来源于stack exchange,提问作者bdream

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 14:40:47