我認爲這是不可能開箱的。 這是原因。 我指的是春天JPA 1.7.3(源代碼可以在這裏找到:http://grepcode.com/snapshot/repo1.maven.org/maven2/org.springframework.data/spring-data-jpa/1.7.3.RELEASE/)
一個JPA規範通過JPA倉庫使用,例如:
myRepo.findAll(mySpec);
此函數的源代碼:
/*
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.JpaSpecificationExecutor#findAll(org.springframework.data.jpa.domain.Specification)
*/
public List<T> findAll(Specification<T> spec) {
return getQuery(spec, (Sort) null).getResultList();
}
這裏是第一問題在這裏:返回類型和查詢類型綁定到實體類型T.你的情況,這意味着返回的結果將是的列表實體。
二問題是選擇列表中getQuery()
功能構成方式:
/**
* Creates a {@link TypedQuery} for the given {@link Specification} and {@link Sort}.
*
* @param spec can be {@literal null}.
* @param sort can be {@literal null}.
* @return
*/
protected TypedQuery<T> getQuery(Specification<T> spec, Sort sort) {
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<T> query = builder.createQuery(getDomainClass());
Root<T> root = applySpecificationToCriteria(spec, query);
query.select(root);
if (sort != null) {
query.orderBy(toOrders(sort, root, builder));
}
return applyRepositoryMethodMetadata(em.createQuery(query));
}
正如你可以看到這種類型的呼叫的明確選擇根(它的類型是T或Stock
在你的情況下)並且在將規範應用於標準查詢之後執行它,它會覆蓋您在規範中執行的任何操作。
雖然有一個解決方法。
可以擴展現有的JPA倉儲類:
public class MyRepositoryImpl<T>
extends SimpleJpaRepository<T, Integer> implements MyRepository<T>
{
,並添加適當的簽名特殊的方法來執行你所需要的:
public <P> P calcAggregate(EntitySpecification<T> spec, SingularAttribute<?,P> column)
{
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery<P> query = criteriaBuilder.createQuery(column.getJavaType());
if (spec != null)
{
Root<T> root = query.from(getDomainClass());
query.where(spec.toPredicate(root, query, criteriaBuilder));
query.select(criteriaBuilder.sum(root.get(column.getName())));
}
TypedQuery<P> typedQuery = em.createQuery(query);
P result = typedQuery.getSingleResult();
return result;
}
然後用它作爲:
myRepo.calcAggregate(mySpec, Stock_.qty);
其中Stock_
是Stock
實體的元模型類。
這是一個非常簡單的例子,只有一個字段,無法選擇聚合操作。它可以根據需要進行擴展。