Гибернация: как создать СУЩЕСТВУЮЩИЙ запрос? (не подзапрос)

#hibernate #hql

#спящий режим #hql

Вопрос:

Например:

 EXISTS ( SELECT * FROM [table] WHERE ... )
  

Как создать такой запрос с помощью Hibernate?

Ответ №1:

HQL не позволяет использовать exists инструкцию. UPD Начиная с Hibernate 5 он поддерживает его как предикат в WHERE

Вы можете использовать несколько подходов:

  1. Для Hibrnate 5: вы можете использовать подзапрос с той же таблицей boolean exists = session.createQuery("select 1 from PersistentEntity where exists (select 1 from PersistentEntity p where ...)").uniqueResult() != null; . Спасибо автору ниже.
  2. count(*) > 0 но это плохо сказывается на производительности Избегайте использования COUNT() в SQL, когда вы могли бы использовать EXISTS()
  3. Используйте boolean exists = session.createQuery("from PersistentEntity where ...").setMaxResults(1).uniqueResult() != null; , но это заставит Hibernate загрузить все поля и выполнить гидратацию объекта, даже если вам нужно просто проверить наличие null.
  4. Используйте session.get(PersistentEntity.class, id) != null , и это будет работать быстрее, если вы включили кэш второго уровня, но это будет проблемой, если вам нужно больше критериев, чем просто id .
  5. Вы можете использовать следующий метод: getSession().createQuery("select 1 from PersistentEntity where ...").uniqueResult() != null)

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

1. Сегодня я голосую против, потому что утверждение «HQL не позволяет использовать exists» неверно. docs.jboss.org/hibernate/orm/5.1/userguide/html_single /…

2. Я не уверен, что новое изменение полностью точное. В вопросе конкретно указано «не подзапрос», но новое решение с exists использует подзапрос. Я также был бы признателен за комментарий о производительности нового exists по сравнению с другими решениями.

Ответ №2:

Если ваша цель — проверить некоторый набор на пустоту, вы можете использовать простой запрос HQL:

 boolean exists = (Long) session.createQuery("select count(*) from PersistentEntity where ...").uniqueResult() > 0
  

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

1. не используйте count(*) для проверки существования, потому что все агрегированные запросы плохо влияют на производительность blog.jooq.org/2016/09/14 /…

Ответ №3:

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

Если бы не было никаких фильтров поиска, предыдущий запрос был бы допустимым, поскольку база данных выполнила бы некоторую оптимизацию с использованием индекса.

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

 boolean exists = session.createQuery("from PersistentEntity where ...").setMaxResults(1).uniqueResult() != null;
  

Ответ №4:

Есть несколько приятных комментариев об использовании EXISTS, но нет примеров. Вот мое решение в Hibernate 5.2:

 boolean exists = session.createQuery( 
                    "SELECT 1 FROM PersistentEntity WHERE EXISTS (SELECT 1 FROM PersistentEntity p WHERE ...)")
            .uniqueResult() != null;
  

Ответ №5:

Кроме того, если вы используете JpaRepository , вы можете легко проверить существование объекта через ORM. Вот пример Kotlin:

 interface UserRepository : JpaRepository<User, Long> {
    fun existsByUsername(username: String): Boolean
}
  

Ответ №6:

Если вы используете JpaRepository , это может быть просто, если критерии существования просты, например:

 Boolean existsByName(String name);
  

Если нет, это решение может быть тем, которое вы ищете.
Напишите запрос, который выглядит как:

 SELECT CASE WHEN count(attr) > 0 THEN TRUE ELSE FALSE
FROM entity
WHERE <condition>
  

Пример:

 SELECT CASE count(pr_id) > 0 THEN TRUE ELSE FALSE
FROM product
WHERE pr_name LIKE 'a__%'
  

протестируйте свой запрос, затем добавьте его в свой репозиторий

 @Repository
public interface FooRepository extends JpaRepository<FooEntity,UUID>{

    @Query(value = "<tested_query_here>", nativeQuery = true)
    Boolean existsByConditionYouWrote(<args>);

}
  

Ответ №7:

Я использовал следующее: SELECT COUNT(e) FROM Entity e . Отлично работал в Spring Data JPA.

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

1. Я получаю java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.Boolean , используя ваш запрос с данными Spring. Не могли бы вы показать полный рабочий пример?

Ответ №8:

Попробуйте:

 "select count(e) > 0 from Entity e where..."
  

Отлично работает с данными Spring.