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" ?
Большое спасибо!
Тим
Ответы
Ответ 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();
}
Кстати, я довольно новичок в этом, поэтому, если по какой-то причине это не очень хорошая идея, дайте мне знать. Спасибо.