Подтвердить что ты не робот

Hibernate: Как установить значение параметра NULL-запроса в HQL?

как установить параметр Hibernate на "null" ? Пример:

Query query = getSession().createQuery("from CountryDTO c where c.status = :status  and c.type =:type")
.setParameter("status", status, Hibernate.STRING)
.setParameter("type", type, Hibernate.STRING);

В моем случае строка состояния может быть нулевой. Я отлаживал это, и hibernate затем генерирует SQL-строку/запрос, подобный этому.... status = null... Это, однако, не работает в MYSQL, так как правильный оператор SQL должен быть "status is null" (Mysql не понимает status = null и оценивает это значение как false, так что никакие записи никогда не будут возвращены для запроса, в соответствии с документами mysql, которые я прочитал...)

Мои вопросы:

  • Почему doesnt Hibernate правильно переводит пустую строку в "null" (а скорее и неправильно создает "= null" )?

  • Каков наилучший способ переписать этот запрос так, чтобы он был нулевым? С nullsafe я имею в виду, что в случае, когда строка состояния имеет значение NULL, чем она должна создать "null" ?

Большое спасибо! Тим

4b9b3361

Ответ 1

  • Я считаю, что hibernate сначала переводит ваш запрос HQL на SQL и только после этого пытается связать ваши параметры. Это означает, что он не сможет переписать запрос с param = ? на param is null.

  • Попробуйте использовать критерии api:

    Criteria c = session.createCriteria(CountryDTO.class);
    c.add(Restrictions.eq("type", type));
    c.add(status == null ? Restrictions.isNull("status") : Restrictions.eq("status", status));
    List result = c.list();
    

Ответ 2

Это не проблема Hibernate (это просто природа SQL), и ДА, есть решение для SQL и HQL:

@Peter Lang имел правильную идею, и у вас был правильный запрос HQL. Я думаю, вам просто нужен новый чистый прогон, чтобы забрать изменения запроса; -)

Приведенный ниже код абсолютно работает, и это здорово, если вы сохраняете все свои запросы в orm.xml

from CountryDTO c where ((:status is null and c.status is null) or c.status = :status) and c.type =:type

Если ваш параметр String равен null, запрос будет проверять, имеет ли статус строки значение null. В противном случае он прибегает к сопоставлению с знаком равенства.

Примечания:

Проблема может быть специфической причудой MySql. Я тестировал только Oracle.

В приведенном выше запросе предполагается, что существуют строки таблицы, где c.status имеет значение null

Предложение where приоритетно, так что сначала проверяется параметр.

Имя параметра "type" может быть зарезервированным словом в SQL, но это не имеет значения, поскольку оно заменяется до выполнения запроса.

Если вам нужно пропустить: status where_clause вообще; вы можете сделать так:

from CountryDTO c where (:status is null or c.status = :status) and c.type =:type

и это эквивалентно:

sql.append(" where ");
if(status != null){
  sql.append(" c.status = :status and ");
}
sql.append(" c.type =:type ");

Ответ 3

javadoc для setParameter(String, Object) является явным, говоря, что значение Object должно быть не нулевым. Позор, что он не генерирует исключение, если в него передается значение null.

Альтернативой является setParameter(String, Object, Type), что позволяет использовать нулевые значения, хотя я не уверен, какой параметр Type был бы наиболее подходящим здесь.

Ответ 4

Я не пробовал это, но что произойдет, если вы дважды используете :status для проверки NULL?

Query query = getSession().createQuery(
     "from CountryDTO c where ( c.status = :status OR ( c.status IS NULL AND :status IS NULL ) ) and c.type =:type"
)
.setParameter("status", status, Hibernate.STRING)
.setParameter("type", type, Hibernate.STRING);

Ответ 5

Кажется, вам нужно использовать is null в HQL (что может привести к сложным перестановкам, если имеется более одного параметра с нулевым потенциалом.), но вот возможное решение:

String statusTerm = status==null ? "is null" : "= :status";
String typeTerm = type==null ? "is null" : "= :type";

Query query = getSession().createQuery("from CountryDTO c where c.status " + statusTerm + "  and c.type " + typeTerm);

if(status!=null){
    query.setParameter("status", status, Hibernate.STRING)
}


if(type!=null){
    query.setParameter("type", type, Hibernate.STRING)
}

Ответ 6

Для реального запроса HQL:

FROM Users WHERE Name IS NULL

Ответ 7

HQL поддерживает coalesce, что позволяет уродливые обходные пути, например:

where coalesce(c.status, 'no-status') = coalesce(:status, 'no-status')

Ответ 8

Вы можете использовать

Restrictions.eqOrIsNull("status", status)

insted

status == null ? Restrictions.isNull("status") : Restrictions.eq("status", status)

Ответ 9

Вот решение, которое я нашел на Hibernate 4.1.9. Мне пришлось передать параметр в свой запрос, который иногда может иметь значение NULL. Поэтому я передал использование:

setParameter("orderItemId", orderItemId, new LongType())

После этого я использую следующее предложение where в моем запросе:

where ((:orderItemId is null) OR (orderItem.id != :orderItemId))

Как вы можете видеть, я использую метод Query.setParameter(String, Object, Type), где я не мог использовать Hibernate.LONG, который я нашел в документации (вероятно, это было в более старых версиях). Для полного набора параметров параметра типа проверьте список класса реализации интерфейса org.hibernate.type.Type.

Надеюсь, это поможет!

Ответ 10

это, похоже, работает как хорошо →

@Override
public List<SomeObject> findAllForThisSpecificThing(String thing) {
    final Query query = entityManager.createQuery(
            "from " + getDomain().getSimpleName() + " t  where t.thing = " + ((thing == null) ? " null" : " :thing"));
    if (thing != null) {
        query.setParameter("thing", thing);
    }
    return query.getResultList();
}

Кстати, я довольно новичок в этом, поэтому, если по какой-то причине это не очень хорошая идея, дайте мне знать. Спасибо.