【问题标题】:Spring Boot JPA hierarchical category productsSpring Boot JPA 分层类产品
【发布时间】:2022-01-21 06:53:50
【问题描述】:

这是我的类别表。

@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 的类别获取产品,我必须编写这么长的方法。我不想为每个深度都写方法。我怎样才能简化?

【问题讨论】:

    标签: java spring-boot spring-data-jpa


    【解决方案1】:

    可能有一种聪明的方法可以通过查询来做到这一点,但这里有一些可行的方法,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);
        }
    }
    

    【讨论】:

    • 感谢您的回答,但我认为这不是一个好的解决方案,因为如果有深度为 20 的类别,产品获取查询可能会工作超过 100 次,所以它会很慢。所以如果有这么多的类别,这不是一个好的解决方案。我还想稍后在此查询中添加分页。有了这个解决方案,我认为这是不可能的。
    • 你用的是什么 sql 风格?这可能对您有用:stackoverflow.com/questions/47341764/… 然后您只需将其作为本机查询放在您的存储库中。
    • 看起来不错,可能这行得通。但我做了一个不同的解决方案。感谢您的帮助。
    【解决方案2】:

    我在代码中添加了最大深度检查。对我来说最大深度是 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);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-06-08
      • 2021-09-05
      • 1970-01-01
      • 1970-01-01
      • 2014-12-26
      • 2019-11-03
      • 2019-02-21
      • 2017-09-17
      相关资源
      最近更新 更多