web-dev-qa-db-ja.com

Hibernate:HQLでNULLクエリパラメータ値を設定する方法

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

私の場合、ステータス文字列はnullにできます。私はこれをデバッグし、hibernateはこのようなSQL文字列/クエリを生成します....status = null...ただし、これはMYSQLでは機能しません。正しいSQLステートメントは「status is null "(MySQLはstatus = nullを理解せず、これをfalseと評価するため、これまでに読んだmysqlのドキュメントによると、クエリに対してレコードは返されません...)

私の質問:

  1. なぜHibernateがヌル文字列を「is null」に正しく変換しないのですか(そして、むしろ間違って「= null」を作成するのですか)。

  2. このクエリをnullセーフにするために書き換える最良の方法は何ですか? nullsafeでは、「ステータス」文字列がnullの場合、「is null」を作成する必要があるということですか?

どうもありがとうございました!ティム

56
tim
  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();
    
39
Sergey Demin

これはHibernate固有の問題ではなく(単なるSQLの性質です)、YESがありますIS 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の場合、クエリは行のステータスも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 ");
26
egallardo

setParameter(String, Object)のjavadoc は明示的であり、Objectの値はnull以外でなければなりません。ただし、nullが渡されても例外がスローされないのは残念です。

代替手段は setParameter(String, Object, Type) で、これはdoesがnull値を許可しますが、Typeパラメータはここで最も適切です。

12
skaffman

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)
}
5
Eran Medan

私はこれを試しませんでしたが、:statusを2回使用して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);
4
Peter Lang

HQLは coalesce をサポートしているため、次のようない回避策が可能です。

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

実際のHQLクエリの場合:

FROM Users WHERE Name IS NULL
3
Chris S

使用できます

Restrictions.eqOrIsNull("status", status)

の代わりに

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

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インターフェースの実装クラスのリストを確認してください。

お役に立てれば!

1