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

tim*_*tim 57 java null hibernate

如何将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);
Run Code Online (Sandbox Code Playgroud)

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

我的问题:

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

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

非常感谢你!蒂姆

小智 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();
    
    Run Code Online (Sandbox Code Playgroud)


ega*_*rdo 28

这不是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为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 ");
Run Code Online (Sandbox Code Playgroud)


ska*_*man 13

对的javadocsetParameter(String, Object)是明确的,说对象值必须非空.遗憾的是,如果传入null,它不会抛出异常.

另一种方法是setParameter(String, Object, Type),它确实允许空值,虽然我不知道什么Type参数是最合适的位置.

  • 仅供参考,它实际上是JDBC的"功能":http://bugs.sun.com/bugdatabase/view_bug.do?bug_id = 4312435 Hibernate使用JDBC的`PreparedStatement.setNull()`来绑定`null`参数 (2认同)

Era*_*dan 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)
}
Run Code Online (Sandbox Code Playgroud)

  • 看起来像老sql查询构建给我.对于像这样的东西坚持标准api.亲手写的hql非常容易出错. (3认同)

Arj*_*jan 5

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

where coalesce(c.status, 'no-status') = coalesce(:status, 'no-status')
Run Code Online (Sandbox Code Playgroud)