JPA条件查询计数

时间:2018-01-29 12:34:03

标签: jpa count persistence criteria builder

我使用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))时,有人会解释我的区别吗?

1 个答案:

答案 0 :(得分:0)

AbstractQuery.from的{​​{3}}回答了您的问题:

  

创建并添加与给定实体相对应的查询根形成具有任何现有根的笛卡尔积

由于您两次调用from,并将where子句定义为仅涉及其中一个根,因此查询将返回“过滤”中的40行&#39;与未经过滤的&#39;结果的80结果交叉连接。根。