Группа запросов JPA Criteria использует только идентификатор

Это образец сущности:

public class Account{

   @Id
   Long id
   Double remaining;
   @ManyToOne
   AccountType type
}

public class AccountType{
   @Id
   Long id;
   String name;
}  

Теперь я создаю критерий запроса с Join как:

CriteriaBuilder criteriaBuilder = getEntityManager().getCriteriaBuilder();
CriteriaQuery criteriaQuery = criteriaBuilder.createquery();
Root<Account> accountRoot = criteriaQuery.from(Account.class);
Join<Account, AccountType> typeJoin = accountRoot.join(Account_.type);

criteriaQuery.multiSelect(
    typeJoin,
    criteriaBuilder.sum(accountRoot.get(Account_.remaining))
);

criteriaQuery.groupBy(typeJoin);
Query query = getEntityManager().createQuery(criteriaQuery);
query.getResultList();  

Приведенный выше код генерирует команду Sql следующим образом:

select accType.id, accType.name, sum(acc.remaining)
from account acc join accType on acc.accounttype_id = accType.id
group by accType.id  

Вышеупомянутый код работает в PosgreSQL, но не может работать в Oracle, потому что в нем выберите accType.name, который не появляется в предложении group by.

обновление:
Я думаю, что мой вопрос не ясен для вас. Мой вопрос не о поведении PostgreSQL или Oracle в group by, У меня вопрос такой:
я использую typeJoin в group by пункт (это означает, что я ожидаю, что в спящем режиме использовать все поля AccountType в group by), но почему в спящем режиме просто используйте поле идентификации на group by? если я буду использовать только поле идентичности в group by тогда я могу использовать следующее утверждение:

criteriaQuery.groupBy(typeJoin.get(AccountType_.id)) ;

2 ответа

JPA/Hibernate не включает автоматически все свойства объектов в предложение group by, поэтому вы должны указать их вручную:

CriteriaBuilder criteriaBuilder = getEntityManager().getCriteriaBuilder();
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
Root<Account> accountRoot = criteriaQuery.from(Account.class);
Join<Account, AccountType> typeJoin = accountRoot.join(Account_.type);

criteriaQuery.multiSelect(
    typeJoin.get("id"),
    typeJoin.get("name"),
    criteriaBuilder.sum(accountRoot.get(Account_.remaining))
);

criteriaQuery.groupBy(typeJoin.get("id"), typeJoin.get("name"));
Query query = getEntityManager().createQuery(criteriaQuery);
query.getResultList();  

Если используется GROUP BY, Oracle требует, чтобы каждый столбец в списке выбора был в GROUP BY.
PostgreSQL такой же, за исключением того, что при группировании по первичному ключу он позволяет выбрать любой столбец.

Из документов Oracle

В запросе, содержащем предложение GROUP BY, элементами списка выбора могут быть агрегатные функции, выражения GROUP BY, константы или выражения, включающие одно из них.

Из документов PostgreSQL

Когда присутствует GROUP BY или присутствуют какие-либо агрегатные функции, недопустимо, чтобы выражения списка SELECT ссылались на несгруппированные столбцы, кроме как внутри агрегатных функций или когда несгруппированный столбец функционально зависит от сгруппированных столбцов, поскольку в противном случае было бы больше чем одно возможное значение, которое нужно вернуть для разгруппированного столбца. Функциональная зависимость существует, если сгруппированные столбцы (или их подмножество) являются первичным ключом таблицы, содержащей несгруппированный столбец.

Другие вопросы по тегам