使用标准 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(未经测试,取自Can I get the SQL string from a JPA query object?):
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();
另一种方法可能是将查询存储在文本文件中并添加代码以从那里读取它。