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.from
的 Javadoc 回答了您的问题:
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 个结果交叉连接。
我在使用 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.from
的 Javadoc 回答了您的问题:
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 个结果交叉连接。