2016-01-04 1 views
1

У меня есть два метода: один пытается суммировать поле numMinutes на объекте, используя метод CriticalBuilder sum, другой возвращает список сущностей и ручной цикл через них и суммирует поле numMinutes.Запрос суммы JPA Criteria Builder, который идентичен другому запросу, возвращающему список, не генерирует никакого sql и просто возвращает 0

Первый метод возвращает 0, но второй возвращает правильный ответ. При диагностике этого я включил печать SQL в моем persistence.xml, и первый метод ничего не печатает. Когда отладка HQL довольно тождественна, как вы ожидали.

Два метода ниже, мой вопрос: почему первый из них настолько сломан, и как я должен это делать?

Сломанный метод пытается суммировать значения на базы данных слоя:

public int getTotalTimeRecordedForContract(SupplierServiceContract contract) { 
    CriteriaBuilder builder = getEntityManager().getCriteriaBuilder(); 
    CriteriaQuery<Integer> criteria = builder.createQuery(Integer.class); 
    Root<TimeUserTransaction> root = criteria.from(TimeUserTransaction.class); 

    List<Predicate> allPredicates = new ArrayList<Predicate>(); 
    allPredicates.add(
     builder.between(root.get(TimeUserTransaction_.dateRecorded), contract.getStartDate(), contract.getExpiryDate()) 
    ); 
    allPredicates.add(
     builder.equal(root.get(TimeUserTransaction_.transaction).get(TransactionPlus_.supplierService), contract.getSupplierService()) 
    ); 

    TypedQuery<Integer> query = this.getEntityManager().createQuery(
     criteria.select(builder.sum(root.get(TimeUserTransaction_.numMinutes))).where(allPredicates.toArray(new Predicate[allPredicates.size()])) 
    ); 

    return query.getFirstResult(); 
} 

Метод возвращения списка, который должен быть идентичны, за исключением возвращает Allt Eh сущности, не пытаясь агрегировать и просуммировать столбец numMinutes:

public List<TimeUserTransaction> getTimeRecordedForContract(SupplierServiceContract contract) { 
    CriteriaBuilder builder = getEntityManager().getCriteriaBuilder(); 
    CriteriaQuery<TimeUserTransaction> criteria = builder.createQuery(TimeUserTransaction.class); 
    Root<TimeUserTransaction> root = criteria.from(TimeUserTransaction.class); 

    List<Predicate> allPredicates = new ArrayList<Predicate>(); 
    allPredicates.add(
     builder.between(root.get(TimeUserTransaction_.dateRecorded), contract.getStartDate(), contract.getExpiryDate()) 
    ); 
    allPredicates.add(
     builder.equal(root.get(TimeUserTransaction_.transaction).get(TransactionPlus_.supplierService), contract.getSupplierService()) 
    ); 

    TypedQuery<TimeUserTransaction> query = this.getEntityManager().createQuery(
     criteria.select(root).where(allPredicates.toArray(new Predicate[allPredicates.size()])) 
    ); 

    return query.getResultList(); 
} 

JPQL, как представляется, при отладке, для первого метода:

select sum(generatedAlias0.numMinutes) from TimeUserTransaction as generatedAlias0 where (generatedAlias0.dateRecorded between :param0 and :param1) and (generatedAlias0.transaction.supplierService=:param2) 

и для второй:

select generatedAlias0 from TimeUserTransaction as generatedAlias0 where (generatedAlias0.dateRecorded between :param0 and :param1) and (generatedAlias0.transaction.supplierService=:param2) 

Что озадачивает меня еще больше, как если первый метод генерирует HQL, почему не тогда, что в свою очередь JPQL и запустить, что в базе данных.

Я использую спящий режим для JPA, подключающегося к базе данных mysql - на всякий случай это актуально.

+0

может быть метод суммы по реализации в Hibernate критериев сломан? И когда вы просто используете эквивалентный JPQL напрямую? Реализация JPA, которую я использую (DataNucleus), переопределяет toString() запроса критериев, чтобы я мог видеть, что JPQL он приравнивается к ... возможно, у Hibernate есть такая опция –

ответ

0

Вам не нужен .groupBy(root.get(TimeUserTransaction_.numMinutes)). GROUP BY требуется, если вы выбираете несколько столбцов и используете один столбец с функцией Aggegrate, такой как count, sum. Поскольку вы выбираете только сумму numMinutes, вам не нужно это делать.

Когда вы сделаете это, он сгруппирует все уникальные numMinutes с его суммой. Если som numMinutes имеют 0, то они также будут суммированы с 0 и будут сгруппированы вместе. 0 будет на вершине, потому что это будет упорядочено по возрастанию по умолчанию и query.getFirstResult(); вернет 0.

public int getTotalTimeRecordedForContract(SupplierServiceContract contract) { 
    CriteriaBuilder builder = getEntityManager().getCriteriaBuilder(); 
    CriteriaQuery<Integer> criteria = builder.createQuery(Integer.class); 
    Root<TimeUserTransaction> root = criteria.from(TimeUserTransaction.class); 

    List<Predicate> allPredicates = new ArrayList<Predicate>(); 
    allPredicates.add(
     builder.between(root.get(TimeUserTransaction_.dateRecorded), contract.getStartDate(), contract.getExpiryDate()) 
    ); 
    allPredicates.add(
     builder.equal(root.get(TimeUserTransaction_.transaction).get(TransactionPlus_.supplierService), contract.getSupplierService()) 
    ); 

    TypedQuery<Integer> query = this.getEntityManager().createQuery(
     criteria.select(builder.sum(root.get(TimeUserTransaction_.numMinutes))).where(allPredicates.toArray(new Predicate[allPredicates.size()])); 
    ); 

    return query.getFirstResult(); 
} 
+0

Извините - я оставил группуBy там с того момента, когда я пытался из предложенных исправлений - код выходит из строя независимо от группыBy. Я редактировал код, чтобы отразить это сейчас. Спасибо за внимание, но это неправильный ответ ... –

Смежные вопросы