我试图通过以下关系(仅显示父母)来说明一对多关系的总和:
@Entity
@Table(name = "Parent")
public class Parent implements Serializable {
private static final long serialVersionUID = -7348332185233715983L;
@Id
@Basic(optional = false)
@Column(name = "PARENT_ID")
private Long parentId;
@OneToMany
@JoinColumn(name="CHILDREN", referencedColumnName="PARENT_ID")
private List<Child> children;
@Formula("(select sum(select height from children))")
private BicDecimal totalHeight
}
这是非常直接的,没有任何限制,甚至有静态限制。虽然动态限制子列表但我遇到了麻烦。
就我而言,我正在使用spring数据和jpa。我正在使用规范来限制孩子,并且我正在获得适当的孩子列表,但显然总和仍然是不受限制的孩子,因为@Formula标签中没有where子句。
出于性能原因,我不想在java中迭代列表,因为结果是分页的。此外,总和不是分页结果,而是所有结果。
我是Spring Data / JPA的新手。从历史上看,我可以动态构建此查询或使用休眠标准。我可以运行一个完整的单独查询来进行此计算。我不需要使用@Formula注释,因为每次调用只有1个聚合。在hibernate框架中,我可以将select子句声明为“sum(field)”并构建标准。在Spring Data / JPA框架中,我可以构建涵盖标准的规范,但我不知道如何操作查询的选择部分,因为它似乎与实体紧密联系。
如果我知道需要限制哪些字段,则在存储库上使用@Query注释作为自己的查询,但通常字段为空,需要忽略查询。有8个可能的字段,留下256种可能的组合(2 ^ 8)。这在存储库中有太多方法。
切换框架以外的任何想法?
答案 0 :(得分:0)
您是否尝试过JPQL
select sum(d.height) from Parent a join a.children d
如果您不想忽略空值
select sum(d.height) from Parent a left join a.children d
我认为您的其他问题是如何根据属性进行过滤。我的意思是,如果你需要一个包含多种组合的where语句。
为什么不尝试使用List并根据您想要的组合将要应用的所有谓词添加到列表中。实施例
创建查询
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery cq = cb.createQuery(Double.class);
Root<Parent> root = cq.from(Parent.class)
Join<Parent, Child> join = cq.join(("children"));
cq.select(cb.<Double>sum(join.get("height")));
创建谓词列表
List<Predicates> listOfpredicates = new ArrayList<Predicates>();
if(property1 != null && !"".equals(property1){
PatameterExpression<String> p = cb.parameter(String.class, "valueOfproperty1")
listOfpredicates.add(cb.equal(join.get("property1"),p);
}
然后添加到CriteriaQuery
if(listOfPredicates.size() == 1)
cq.where(listOfPredicates.get(0))
else
cq.where(cb.and(listOfPredicates.toArray(new Predicate[0])));
最后执行查询。
TypedQuery<Double> q = em.createQuery(cq);
q.getResultList();
这将以任意组合动态创建您的查询。
答案 1 :(得分:0)
发布这个老问题的答案,因为我最近遇到了类似的问题。
我决定使用一个自定义存储库,其中包含一个基于传入其中的任何规范进行聚合的方法。可以组合规范以组成动态标准(请参阅org.springframework.data.jpa.domain.Specifications)
所以我的上面儿童身高问题的存储库如下所示:
package something
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Repository;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
@Repository
public class ChildHeightRepository {
@PersistenceContext
EntityManager entityManager;
public Long getTotalHeight(Specification<Child> spec) {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery query = cb.createQuery(Long.class);
Root root = query.from(Child.class);
return ((Long) entityManager.createQuery(
query.where(spec.toPredicate(root, query, cb))
.select(cb.sum(root.get("height")))).getSingleResult());
}
}
答案 2 :(得分:0)
晚了6年,但要花一些时间才能使它起作用,这是我为您的映射所做的工作:
generate_series()
您需要照顾的东西:
with from_to (start_date, end_date) as (
values (timestamp '2020-11-01 16:30:00', timestamp '2020-11-03 18:30:00')
)
select g.nr as row,
g.d::date + case
when g.d::date = start_date::date and start_date::time > time '16:00' then start_date::time
else time '16:00'
end as start_date,
g.d::date + case
when g.d::date = end_date::date and end_date::time < time '21:00' then end_date::time
else time '21:00'
end as end_date
from from_to
cross join generate_series(start_date, end_date, interval '1 day') with ordinality as g(d,nr)
order by g.nr;
,否则sql的语法将无法正确翻译。