Spring Boot JPA分级分类产品

Spring Boot JPA hierarchical category products

这是我的类别 table。

@Getter
@Setter
@NoArgsConstructor
@Entity
public class Category {

    @Id
    @GeneratedValue
    private long id;

    private String name;

    private String imageFileName;

    private int depth;

    @ManyToOne
    private Category parentCategory;

    @OneToMany(mappedBy = "parentCategory")
    private List<Category> childCategories;

    @OneToMany(mappedBy = "category")
    private List<Product> products;

    private boolean deleted;

}

这里是仅适用于 0 和 1 深度类别的解决方案。

public List<Product> getByCategoryId(long categoryId) {
    Category category = categoryService.getById(categoryId);
    if (category.getDepth() == 0) {
        return productRepository.findByCategoryParentCategoryAndDeletedFalse(category);
    }
    return productRepository.findByCategoryAndDeletedFalse(category);
}

我想按类别 ID 获取所有产品。例如,如果我想按深度为 10 的类别获取产品,我必须编写这么长的方法。我不想为每个深度都写方法。我该怎么做简化器?

可能有一种巧妙的方法可以通过查询来完成此操作,但这里有一些可行的方法,JPA 应该为您获取嵌入式实体,而您无需执行任何额外的查询。

基本思想是递归爬行直到达到一定深度。

public List<Product> getByCategoryId(long categoryId, int depth) {
    Category category = categoryService.getById(categoryId);

    Set<Product> result = new HashSet<>();

    searchUntilDepth(result, category,depth);

    return new ArrayList<>(result);
}

private void searchUntilDepth(Set<Product> foundProducts, Category cat, int depth) {
    foundProducts.addAll(cat.getProducts());

    if (cat.getDepth() >= depth) {
        return;
    }

    for (Category child : cat.getChildCategories()) {
        searchUntilDepth(foundProducts, child, depth);
    }
}

我在我的代码中添加了最大深度检查。最大深度对我来说是 4。深度可以是 1 或 2 或 3 或 4。我的解决方案就是这样。目前看起来效果不错。

@Query("select p from Product p " +
            "left join Category c1 on p.category.id = c1.id and c1.deleted = false " +
            "left join Category c2 on c1.parentCategory.id = c2.id and c2.deleted = false " +
            "left join Category c3 on c2.parentCategory.id = c3.id and c3.deleted = false " +
            "left join Category c4 on c3.parentCategory.id = c4.id and c4.deleted = false " +
            "where p.deleted = false and " +
            "(c1.id = :#{#category.id} or c2.id = :#{#category.id} or c3.id = :#{#category.id} or c4.id = :#{#category.id})")
List<Product> getByCategoryAndDeletedFalse(@Param("category") Category category);