我有一个DB2数据库函数声明如下:
CREATE FUNCTION MYDB.FN_ISNEWSCOVERAGE(NEWS_ID INTEGER, USERID VARCHAR(50))
RETURNS INTEGER
...
包含一些复杂的SQL逻辑并返回1或0(表示true / false)。
我正在尝试使用该函数来过滤使用JPA Criteria API(在Spring 3 / Hibernate上)构建的查询中的结果,如下所示:
EntityManager em = ...
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<News> cq = cb.createQuery(News.class);
Root<News> news = cq.from(News.class);
Predicate criteria = cb.conjunction();
...
String userid = ...
criteria = cb.and( criteria,
cb.equal( cb.function( "MYDB.FN_ISNEWSCOVERAGE",
Long.class,
news.get("id"),
cb.<String>literal( userid ) ),
1 )
);
...
TypedQuery<News> tq = em.createQuery(cq);
List<News> results = tq.getResultList();
...
问题是当运行生成的查询时,db2会抛出错误:
Caused by: com.ibm.db2.jcc.b.eo: DB2 SQL Error: SQLCODE=-418, SQLSTATE=42610, SQLERRMC=null, DRIVER=3.53.95
描述here。看来问题是生成的SQL包含'?'其中一个MYDB.FN_ISNEWSCOVERAGE函数参数的位置参数 - 这是生成的查询字符串的相关部分:
SELECT ... from MYDB.NEWS news0_ where 1=1 and news0_.ACTIVE=? and MYDB.FN_ISNEWSCOVERAGE(news0_.NEWS_ID, ?)=1
如果我将生成的查询复制到sql客户端并用文字值替换位置参数,则查询运行正常。
从JPA Criteria API调用数据库函数时,有没有办法可以避免此错误?
更新
我已经意识到我可以通过使用子查询将文字函数参数替换为路径表达式来解决问题,如下所示:
Subquery<News> sq = cq.subquery(News.class);
Root<News> sqNews = sq.correlate(news);
Root<User> sqUser = sq.from(User.class);
sq.select(news)
.where(
cb.equal(sqUser.get("id"), userid),
cb.equal(cb.function("MYDB.FN_ISNEWSCOVERAGE",
Long.class,
sqNews.get("id"),
sqUser.get("id")),
1)
);
criteria = cb.and(cb.exists(sq));
但是,此解决方法可能不适用于其他情况 - 是否有更好的解决方案?
答案 0 :(得分:0)
尽管这是一个老问题,但我们今天遇到了同样的问题。
由于问题是 '?' 参数,我们选择强制 hibernate 内联文字。
properties.put(AvailableSettings.CRITERIA_LITERAL_HANDLING_MODE, LiteralHandlingMode.INLINE);
有关 hibernate 如何处理文字的进一步说明:https://vladmihalcea.com/how-does-hibernate-handle-jpa-criteria-api-literals/