2016-08-13 46 views
0

我想和功能在春季規格如下: -春季規格的額頭功能

@Override 
    public Predicate toPredicate(Root<Stock> root, CriteriaQuery<?> query, CriteriaBuilder builder) { 
Path expression = root.get("qty"); 
query.select(builder.sum(expression)); 
return null; 
} 

我想下面執行的查詢:

SELECT SUM(o.qty) FROM Stock o; 

但春天也沒有創造和功能它只是創建爲:

SELECT o.qty FROM Stock o 

我檢查了這麼多堆棧溢出問題,但沒有答案規範的方式,大多數人使用JPQL@Query註釋爲此。但是我的進一步查詢和設計非常複雜,所以我只能使用規範。因爲我需要完全動態的查詢。

也有類似的question以及this

回答

0

我認爲這是不可能開箱的。 這是原因。 我指的是春天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實體的元模型類。

這是一個非常簡單的例子,只有一個字段,無法選擇聚合操作。它可以根據需要進行擴展。