如何将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文档,不会为查询返回任何记录...)
我的问题:
为什么没有Hibernate
正确地将空字符串转换为“is null”(而且错误地创建“= null”)?
重写此查询以使其为空安全的最佳方法是什么?使用nullsafe,我的意思是,如果“status”字符串为null,则应该创建“is null”?
非常感谢! 添
答案 0 :(得分:39)
我相信hibernate会首先将您的HQL查询转换为SQL,然后才会尝试绑定您的参数。这意味着它无法将查询从param = ?
重写为param is null
。
尝试使用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();
}
顺便说一下,我对此很陌生,所以如果出于任何原因这不是一个好主意,请告诉我。感谢。