Как правильно определить, возвращено ли существующее предложение JPA Criteria Query true или false?

Я не знаю, как выполнить запрос критериев JPA, который возвращает логический вывод.

Цель состоит в том, чтобы запрос критериев выглядел следующим образом при отображении в Oracle:

select 1 from dual where exists ( ... );

Часть where exists (...) я выполнил с подзапросом. Я борюсь с внешним запросом.

Практическое использование этого состоит в том, чтобы определить, возвращает ли этот подзапрос в предложении exists true или false.

Вот что я написал:

CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();

CriteriaQuery<Object> query = criteriaBuilder.createQuery();
query.from(Boolean.class);
query.select(criteriaBuilder.literal(true));

Subquery<Location> subquery = query.subquery(Location.class);
Root<Location> subRootEntity = subquery.from(Location.class);
subquery.select(subRootEntity);

Path<?> attributePath = subRootEntity.get("State");
Predicate predicate = criteriaBuilder.equal(attributePath, criteriaBuilder.literal("TX"));
subquery.where(predicate);
query.where(criteriaBuilder.exists(subquery));

TypedQuery<Object> typedQuery = em.createQuery(query);


В последней строке выводится ошибка, утверждающая, что "Boolean не является сущностью". Я думаю, что моя проблема заключается в том, что я не знаю, как выразить часть запроса «from», чтобы результат выдавал 1 или 0/true или false, а не сущность.

Я знаю, что могу получить любой объект, а затем проверить, имеет ли список результатов размер 1.

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

Возможно ли это вообще?

Спасибо! Эдуардо


person Edy Bourne    schedule 18.07.2011    source источник
comment
Нет, вы не можете сделать это напрямую, но распространенным способом является проверка количества набора результатов, т. Е. Если количество больше нуля, тогда true, иначе false.   -  person Shahzeb    schedule 18.07.2011


Ответы (6)


Вы можете сделать выбор для одного свойства (например, идентификатора) и установить максимальное количество возвращаемых результатов равным 1, чтобы убедиться, что БД не выполняет больше работы, чем необходимо (например, подсчет всех экземпляров). Тогда ваш список результатов будет либо пустым (exists = false), либо содержать один элемент (exists = true).

person dimo    schedule 05.04.2012
comment
Это то, что я искал, способ добиться этого, не заставляя СУБД работать больше, чем необходимо. Спасибо!! - person Edy Bourne; 03.12.2012

Да, это возможно. Предполагая, что у вас есть объект, соответствующий вашей таблице dual, вы захотите использовать этот класс объектов в CriteriaQuery#from.

CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();

CriteriaQuery<Boolean> query = criteriaBuilder.createQuery(Boolean.class);
query.from(dual.class);
query.select(criteriaBuilder.literal(true));

Subquery<Location> subquery = query.subquery(Location.class);
Root<Location> subRootEntity = subquery.from(Location.class);
subquery.select(subRootEntity);

Path<?> attributePath = subRootEntity.get("State");
Predicate predicate = criteriaBuilder.equal(attributePath, criteriaBuilder.literal("TX"));
subquery.where(predicate);
query.where(criteriaBuilder.exists(subquery));

TypedQuery<Boolean> typedQuery = em.createQuery(query);
person Matthew T. Staebler    schedule 06.04.2013

Спящий режим 5 работает:

Subquery<Integer> subquery = query.subquery(Integer.class);
Root<Location> subRootEntity = subquery.from(Location.class);
subquery.select(criteriaBuilder.literal(1));

Path<?> attributePath = subRootEntity.get("State");
Predicate predicate = criteriaBuilder.equal(attributePath, criteriaBuilder.literal("TX"));
subquery.where(predicate);
query.where(criteriaBuilder.exists(subquery));
person user3158918    schedule 03.05.2017

Я знаю, что это старый вопрос, но для всех, кто ищет: как насчет того, чтобы попытаться использовать аннотацию Spring jpa @Query и запрос выбора случая (в зависимости от вашей реализации БД) с методом, который возвращает логическое значение. Например (MySQL):

@Query("SELECT CASE WHEN COUNT(l) > 0 THEN TRUE ELSE FALSE END FROM Location l WHERE l.state=?1")
boolean locationForStateExists(String state);

Иногда просто использование строки запроса в @Query может спасти жизнь, когда именованные методы JPA или построителя запросов не совсем делают то, что вы хотите.

person David P    schedule 16.03.2016
comment
Это зависит от count(), что является фундаментальной проблемой. Hibernate не поддерживает ключевое слово exists, за исключением предложения where, которое не выполняет то, о чем просит OP. Выбор count потенциально может быть очень медленным (в зависимости от сложности предложения where, наличия индексов и т. д.), в то время как предложение exists быстро выйдет из строя при первом же появлении. Очень жаль, что JPA/Hibernate не поддерживает эту тривиальную оптимизацию. - person Matt Brock; 01.02.2017

Я думаю, что проблема в query.from(Boolean.class). Он пытается создать запрос «выбрать объект из логического». Если вам нужен логический тип возвращаемого значения, вам нужно использовать

CriteriaQuery<Boolean> query = criteriaBuilder.createQuery(Boolean.class)

Затем выполните запрос из любой существующей таблицы сущностей, чтобы создать допустимый запрос (возможно, из таблицы подзапроса). Я не думаю, что создание из двойной таблицы работает, за исключением случаев, когда вам удалось сопоставить двойную таблицу.

person user948392    schedule 17.09.2011

Есть ли причина, по которой вся логика должна быть в JPA? Если нет, то почему бы не использовать SELECT COUNT, а затем условное выражение для установки логического значения?

Boolean exists = false;
int count = selectCountQuery();
if (count > 0) {
  exists = true;
}
person Chip McCormick    schedule 17.09.2011