пятница, 3 июня 2011 г.

CriteriaBuilder. Проблема в count-запросе сущностей с составным первичным ключом

Проблема:
Если запрос строится на Criteria API, то существует баг, воспроизводимый при попытке count-запроса для сущности с составным первичным ключом (composite primary key).
Ошибка при этом звучит так:
Caused by: java.sql.SQLException: ORA-00907: missing right parenthesis


Причина:
Запрос формируется в таком виде:
select count((field1, field2)) from MyEntity;

Дело в том, что Hibernate сам ищет идентификаторы сущности и подставляет в count их, а не wildcard (*).
Изучение жалоб говорит о том, что полученный запрос не воспринимается oracle, mysql, зато выполняется в mssql.
Есть также и открытый дефект на трекере Hibernat'а: http://opensource.atlassian.com/projects/hibernate/browse/HHH-5419
Впрочем, он открыт уже почти год. А потому быстрее найти способ обойти проблему, чем ждать централизованного решения.

Решение:
На полноценное решение не тянет, но, уверен, поможет 95% столкнувшихся с проблемой.
Как правило составной идентификатор состоит из нескольких внешних ключей. И наверняка хоть один из них not null. А в этом случае, можно провести count непосредственно по этому полю:
select count(pk1) from MyEntity;

Реализация:
Вместо обычного кода:
CriteriaQuery<Long> query = getCriteriaBuilder().createQuery(Long.class);
Root<MyEntity> from = query.from(MyEntity.class);

query.select(getCriteriaBuilder().count(from));
пишем следующий:
CriteriaQuery<Long> query = getCriteriaBuilder().createQuery(Long.class);
Root<MyEntity> from = query.from(MyEntity.class);
query.select(getCriteriaBuilder().count(from.get(MyEntity_.field1)));

Замечание:
select count(field) from table
Возвращает количество кортежей (строк) таблицы, в которых field is not null, при этом совпадения значений field у кортежей ни на что не влияют.

Комментариев нет:

Отправить комментарий