Hibernate:如何用HQL设置NULL查询参数值?
我怎么能设置一个hibernate参数为“空”? 例:
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可以为空。 我debugging了这个和hibernate,然后生成一个像这样的SQLstring/查询…. status = null
…这然而不能在MYSQL中工作,因为正确的SQL语句必须是“ status is null
”(Mysql不明白status = null,并将其评估为false,以便根据我读过的mysql文档,查询将不会返回任何logging…)
我的问题:
-
为什么
Hibernate
没有正确地将空string转换为“空”(而不是错误地创build“= null”)? -
什么是重写这个查询,以便它是无效的最好的方法是什么? 用nullsafe我的意思是说,在“状态”string为空的情况下,应该创build一个“为空”?
非常感谢你! 蒂姆
-
我相信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();
这不是一个Hibernate的特定问题(它只是SQL本质),是的,这是SQL和HQL的解决scheme:
@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进行testing。
上面的查询假定有表行,其中c.status为空
where子句优先,以便首先检查参数。
参数名称“type”可能是SQL中的一个保留字,但它不应该因为在查询运行之前被replace。
如果您需要完全跳过: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 ");
setParameter(String, Object)
的javadoc是显式的,表示Object的值必须是非空的。 但是,如果传入null,它不会抛出exception。
另一种方法是setParameter(String, Object, Type)
,它允许空值,尽pipe我不确定在这里最适合的Type
参数是什么。
我没有尝试这个,但是当你使用两次: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中使用is null
(如果有多个参数,可能会导致复杂的排列),但是这里有一个可能的解决scheme:
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) }
对于一个实际的HQL查询:
FROM Users WHERE Name IS NULL
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上find的解决scheme。 我不得不传递一个参数给我的查询,有时可以有值NULL。 所以我通过了使用:
setParameter("orderItemId", orderItemId, new LongType())
之后,我在查询中使用以下where子句:
where ((:orderItemId is null) OR (orderItem.id != :orderItemId))
正如你所看到的,我正在使用Query.setParameter(String,Object,Type)方法,在那里我不能使用我在文档中find的Hibernate.LONG(可能是在旧版本中)。 对于types参数的全部选项,请查看org.hibernate.type.Type接口的实现类列表。
希望这可以帮助!
这似乎工作如此 – >
@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(); }
顺便说一句,我很新,所以如果因为任何原因这不是一个好主意,让我知道。 谢谢。