【发布时间】:2012-01-27 00:18:46
【问题描述】:
我有一个 DB2 数据库函数,声明如下:
CREATE FUNCTION MYDB.FN_ISNEWSCOVERAGE(NEWS_ID INTEGER, USERID VARCHAR(50))
RETURNS INTEGER
...
其中包含一些复杂的 SQL 逻辑,返回 1 或 0(表示真/假)。
我正在尝试使用该函数来过滤使用 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));
但是,此解决方法可能不适用于其他情况 - 是否有更好的解决方案?
【问题讨论】:
-
能否在参数标记周围指定一个SQL强制转换函数,如CAST(?AS VARCHAR(50))
-
我不确定该怎么做,因为我无法直接控制 Criteria API 查询生成的 SQL。
-
您想要一些不使用 criteria API 的解决方案吗?
标签: hibernate function jpa db2 criteria-api