標準のJPAでは不可能です。Hibernateは独自の方法setParameterList()
を提供しますが、Hibernateセッションでのみ機能し、JPAでは使用できませんEntityManager
。
私はHibernateの次の回避策を考え出しました。これは理想的ではありませんが、ほぼ標準のJPAコードであり、いくつかの優れたプロパティがあります。
orm.xml
手始めに、名前付きネイティブクエリをファイル内で適切に分離しておくことができます。
<named-native-query name="Item.FIND_BY_COLORS" result-class="com.example.Item">
<query>
SELECT i.*
FROM item i
WHERE i.color IN ('blue',':colors')
AND i.shape = :shape
</query>
</named-native-query>
プレースホルダーは一重引用符で囲まれているため、有効なネイティブJPAクエリです。パラメータリストを設定せずに実行され、他の一致するカラーパラメータが設定されている場合でも正しい結果を返します。
DAOまたはリポジトリクラスにパラメータリストを設定します。
@SuppressWarnings("unchecked")
public List<Item> findByColors(List<String> colors) {
String sql = getQueryString(Item.FIND_BY_COLORS, Item.class);
sql = setParameterList(sql, "colors", colors);
return entityManager
.createNativeQuery(sql, Item.class)
.setParameter("shape", 'BOX')
.getResultList();
}
クエリ文字列を手動で作成する必要はありません。通常どおり、他のパラメータを設定できます。
ヘルパーメソッド:
String setParameterList(String sql, String name, Collection<String> values) {
return sql.replaceFirst(":" + name, String.join("','", values));
}
String getQueryString(String queryName, Class<?> resultClass) {
return entityManager
.createNamedQuery(queryName, resultClass)
.unwrap(org.hibernate.query.Query.class) // Provider specific
.getQueryString();
}
つまり、基本的にはからクエリ文字列を読み取り、orm.xml
パラメータリストを手動で設定してから、ネイティブJPAクエリを作成します。残念ながら、createNativeQuery().getResultList()
結果クラスを渡したにもかかわらず、型なしクエリと型なしリストが返されます。したがって、@SuppressWarnings("unchecked")
。
欠点:クエリを実行せずにアンラップすることは、Hibernate以外のJPAプロバイダーにとってより複雑または不可能な場合があります。たとえば、EclipseLinkでは次のように機能する可能性があります(テストされていない、JPAクエリオブジェクトからSQL文字列を取得できますか?):
Session session = em.unwrap(JpaEntityManager.class).getActiveSession();
DatabaseQuery databaseQuery = query.unwrap(EJBQueryImpl.class).getDatabaseQuery();
databaseQuery.prepareCall(session, new DatabaseRecord());
Record r = databaseQuery.getTranslationRow();
String bound = databaseQuery.getTranslatedSQLString(session, r);
String sqlString = databaseQuery.getSQLString();
別の方法として、クエリをテキストファイルに保存し、そこから読み取るコードを追加することもできます。