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のドキュメントによると、クエリに対してレコードは返されません...)
私の質問:
なぜHibernate
がヌル文字列を「is null」に正しく変換しないのですか(そして、むしろ間違って「= null」を作成するのですか)。
このクエリをnullセーフにするために書き換える最良の方法は何ですか? nullsafeでは、「ステータス」文字列がnullの場合、「is null」を作成する必要があるということですか?
どうもありがとうございました!ティム
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();
これは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 ");
setParameter(String, Object)
のjavadoc は明示的であり、Objectの値はnull以外でなければなりません。ただし、nullが渡されても例外がスローされないのは残念です。
代替手段は setParameter(String, Object, Type)
で、これはdoesがnull値を許可しますが、Type
パラメータはここで最も適切です。
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)
}
私はこれを試しませんでしたが、: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);
HQLは coalesce をサポートしているため、次のようない回避策が可能です。
where coalesce(c.status, 'no-status') = coalesce(:status, 'no-status')
実際の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を使用できませんでした(おそらく古いバージョンにありました)。 typeパラメーターの完全なオプションセットについては、org.hibernate.type.Typeインターフェースの実装クラスのリストを確認してください。
お役に立てれば!