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, которые я прочитал...)

Мои Вопросы:

  1. Почему бы и нет Hibernate правильно перевести нулевую строку в "IS null "(а скорее и ошибочно создает"=null")?

  2. каков наилучший способ переписать этот запрос так, чтобы он был null-безопасным? С nullsafe я имею в виду, что в случае, если строка "status" равна null, чем она должна создать "is null"?

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

10 54

10 ответов:

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

  2. попробуйте использовать критерии 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')

для фактического запроса HQL:

FROM Users WHERE Name IS NULL

можно использовать

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();
}

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