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

我的问题:

  1. 为什么Hibernate没有正确地将空string转换为“空”(而不是错误地创build“= null”)?

  2. 什么是重写这个查询,以便它是无效的最好的方法是什么? 用nullsafe我的意思是说,在“状态”string为空的情况下,应该创build一个“为空”?

非常感谢你! 蒂姆

  1. 我相信Hibernate首先将你的HQL查询翻译成SQL,然后才会尝试绑定你的参数。 这意味着它将无法重写从param = ?查询 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(); 

这不是一个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(); } 

顺便说一句,我很新,所以如果因为任何原因这不是一个好主意,让我知道。 谢谢。