簡體   English   中英

Hibernate:如何使用 HQL 設置 NULL 查詢參數值?

[英]Hibernate: How to set NULL query-parameter value with HQL?

如何將休眠參數設置為“空”? 例子:

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

就我而言,狀態字符串可以為空。 我已經調試了這個,然后休眠然后生成一個像這樣的 SQL 字符串/查詢 .... status = null ... 然而這在 MYSQL 中不起作用,因為正確的 SQL 語句必須是“ status is null ”(Mysql 不理解根據我閱讀的 mysql 文檔,status=null 並將其評估為 false,以便查詢不會返回任何記錄...)

我的問題:

  1. 為什么Hibernate正確地將空字符串轉換為“is null”(而是錯誤地創建“=null”)?

  2. 重寫此查詢以使其為空安全的最佳方法是什么? 使用 nullsafe 我的意思是,在“狀態”字符串為空的情況下,它應該創建一個“為空”?

  1. 我相信 hibernate 首先將您的 HQL 查詢轉換為 SQL,然后才嘗試綁定您的參數。 這意味着它將無法從param = ?重寫查詢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();

這不是特定於 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 為空,則查詢將檢查行的狀態是否也為空。 否則它將求助於與等號進行比較。

筆記:

問題可能是特定的 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 ");

setParameter(String, Object)javadoc是明確的,說 Object 值必須是非空的。 遺憾的是,如果傳入 null,它不會引發異常。

另一種方法是setParameter(String, Object, Type) ,這確實允許空值,雖然我不知道什么Type的參數會在這里是最合適的。

似乎您必須在 HQL 中使用is null (如果有多個參數可能is 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)
}

HQL 支持coalesce ,允許丑陋的解決方法,例如:

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

我沒有嘗試這個,但是當你使用: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 查詢:

FROM Users WHERE Name IS NULL

您可以使用

Restrictions.eqOrIsNull("status", status)

插入的

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

這是我在 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(可能是舊版本)。 類型參數的全套選項,查看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();
}

順便說一句,我對此很陌生,所以如果出於任何原因這不是一個好主意,請告訴我。 謝謝。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM