JPA 条件查询计数

JPA criteria query count

我在使用 CriteriaBuilder 计算实体时遇到问题。首先,我有两个实体 - 类别和项目。类别是对象树,可以有一个父级、多个子类别和项目。 这是我在 mysql:

中的实际数据
Category 0
  Category 0 0
    10 items
  Category 0 1
    10 items
  Category 0 2
    10 items
  Category 0 3
    10 items
Category 1
  Category 1 0
    10 items
  Category 1 1
    10 items
  Category 1 2
    10 items
  Category 1 3
    10 items

类别实体:

@ManyToOne
private Category category;

@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private List<Category> subcategories = new ArrayList<>();

@OneToMany(cascade = CascadeType.ALL)
private List<ItemForSale> items = new ArrayList<>();

public List<Category> getAllCategories() {
    List<Category> categories = new ArrayList<>();
    categories.add(this);
    getSubcategories().forEach((c) -> {
        categories.addAll(c.getAllCategories());
    });
    return categories;
}

我的计数查询应该根据条件对项目进行计数

public int getItemsForSaleCount(Category category) {
    CriteriaBuilder cm = em.getCriteriaBuilder();
    CriteriaQuery<Long> cq = cm.createQuery(Long.class);
    Root<ItemForSale> root = cq.from(ItemForSale.class);
    cq.select(cm.count(cq.from(ItemForSale.class)));
    List<Category> categories = category.getAllCategories();
    if(categories.size() > 1) {
        List<Predicate> predicates = new ArrayList<>();
        categories.forEach((c) -> {
            predicates.add(cm.equal(root.get("category"), c));
        });
        cq.where(cm.or(predicates.toArray(new Predicate[predicates.size()])));
    } else {
        cq.where(cm.equal(root.get("category"), category));
    }
    Query query = em.createQuery(cq);
    return Math.toIntExact((Long) query.getSingleResult());
}

基本上发生的事情是,当我请求类别 0 时,例如查询结果应该是 40,但是 40 * 80 = 3200(正确结果 * 项目总数),当我请求子类别时,结果是 10 * 80 = 800

编辑: 我解决了它,当我用 root 替换 cq.from(ItemForSale.class)) 时它正在工作,有人能解释一下区别吗?

嗯,AbstractQuery.fromJavadoc 回答了您的问题:

Create and add a query root corresponding to the given entity, forming a cartesian product with any existing roots.

由于您调用了 from 两次,并且将 where 子句定义为仅涉及一个根,因此查询 returns 来自 'filtered' 根的 40 行与来自 'unfiltered' 根的 80 个结果交叉连接。