Hibernate:如何使用HQL设置NULL查询参数值?

时间:2010-01-23 14:21:00

标签: java hibernate null

如何将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);

在我的例子中,状态String可以为null。我调试了这个,然后hibernate生成一个像这样的SQL字符串/查询.... status = null ...然而这在MYSQL中不起作用,因为正确的SQL语句必须是“status is null”( Mysql不理解status = null并将其计算为false,因此根据我读过的mysql文档,不会为查询返回任何记录...)

我的问题:

  1. 为什么没有Hibernate正确地将空字符串转换为“is null”(而且错误地创建“= null”)?

  2. 重写此查询以使其为空安全的最佳方法是什么?使用nullsafe,我的意思是,如果“status”字符串为null,则应该创建“is null”?

  3. 非常感谢! 添

10 个答案:

答案 0 :(得分:39)

  1. 我相信hibernate会首先将您的HQL查询转换为SQL,然后才会尝试绑定您的参数。这意味着它无法将查询从param = ?重写为param is null

  2. 尝试使用Criteria 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();
    

答案 1 :(得分:25)

这不是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,则查询将检查行的状态是否也为空。否则它将与等号进行比较。

备注:

问题可能是特定的MySql怪癖。我只用Oracle测试过。

以上查询假定存在c.status为空的表行

优先考虑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 ");

答案 2 :(得分:12)

javadoc for setParameter(String, Object)是显式的,表示Object值必须为非null。遗憾的是,如果传入null,它不会抛出异常。

另一种选择是setParameter(String, Object, Type),其中 允许空值,但我不确定Type参数在这里最合适。

答案 3 :(得分:5)

似乎你必须在HQL中使用is null(如果存在多个具有null潜力的参数,则可能导致复杂的排列。)但这是一个可能的解决方案:

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

答案 4 :(得分: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 :(得分:4)

HQL支持coalesce,允许使用丑陋的解决方法,例如:

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

答案 6 :(得分:3)

对于实际的HQL查询:

FROM Users WHERE Name IS NULL

答案 7 :(得分:1)

您可以使用

Restrictions.eqOrIsNull("status", status)

而不是

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

答案 8 :(得分:1)

这是我在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(可能是旧版本)。有关type参数的完整选项集,请检查org.hibernate.type.Type接口的实现类列表。

希望这有帮助!

答案 9 :(得分:-1)

这似乎也起作用 - >

@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();
}
顺便说一下,我对此很陌生,所以如果出于任何原因这不是一个好主意,请告诉我。感谢。