Hibernate: Как установить нулевое значение параметра запроса с помощью 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);
в моем случае строка состояния может быть null. Я отладил это и спящий режим затем генерирует строку SQL/запрос, как это ....status = null
... Однако это не работает в MYSQL, так как правильный оператор SQL должен быть "status is null
" (Mysql не понимает status=null и оценивает это как false, так что никакие записи никогда не будут возвращены для запроса, согласно документам mysql, которые я прочитал...)
Мои Вопросы:
Почему бы и нет
Hibernate
правильно перевести нулевую строку в "IS null "(а скорее и ошибочно создает"=null")?каков наилучший способ переписать этот запрос так, чтобы он был null-безопасным? С nullsafe я имею в виду, что в случае, если строка "status" равна null, чем она должна создать "is null"?
большое спасибо! Тим
10 ответов:
Я считаю, что hibernate сначала переводит ваш запрос HQL в SQL и только после этого пытается связать ваши параметры. Это означает, что он не сможет переписать запрос из
param = ?
toparam 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();
Это не спящий режим конкретной проблемы (это просто природа 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
если строка вашего параметра равна нулю, то запрос будет проверять, если статус строки также равен нулю. В противном случае он прибегнет к сравнению со знаком равенства.
Примечания:
проблема может быть специфической причудой MySql. Я только тестировал с Oracle.
приведенный выше запрос предполагает, что есть строки таблицы, где c.status равен null
предложение where имеет приоритет, так что параметр проверяется первым.
имя параметра 'type' может быть зарезервированным словом в SQL, но это не должно иметь значения, так как он заменяется перед выполнением запроса.
Если вам нужно было пропустить: статус 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 ");
The javadoc для
setParameter(String, Object)
является явным, говоря, что значение объекта должно быть ненулевым. Жаль, что он не создает исключение, если передается значение null.альтернатива
setParameter(String, Object, Type)
, который тут разрешить значения null, хотя я не уверен, чтоType
параметр был бы наиболее подходящим здесь.
Кажется, вы должны использовать
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) }
Я не пробовал это, но что происходит, когда вы используете
: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);
HQL поддерживает коалесцируют, учитывая уродливые обходные пути, такие как:
where coalesce(c.status, 'no-status') = coalesce(:status, 'no-status')
можно использовать
Restrictions.eqOrIsNull("status", status)
вместо
status == null ? Restrictions.isNull("status") : Restrictions.eq("status", status)
вот решение, которое я нашел на Hibernate 4.1.9. Мне пришлось передать параметр в мой запрос, который иногда может иметь значение NULL. Поэтому я передал использование:
setParameter("orderItemId", orderItemId, new LongType())
после этого, я использую следующее предложение where в запрос:
where ((:orderItemId is null) OR (orderItem.id != :orderItemId))
Как вы можете видеть, я использую запрос.setParameter (String, Object, Type) метод, где я не мог использовать Hibernate.Долго, что я нашел в документации (вероятно, это было на более старых версиях). Для полного набора опций типа параметр, проверьте список классов реализации организации.зимовать.тип.Тип интерфейса.
надеюсь, что это помогает!
это, кажется, работает как wel ->
@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(); }
кстати, я довольно новичок в этом, поэтому если по какой-либо причине это не хорошая идея, дайте мне знать. Спасибо.