我正在开发一个 Java 应用程序,最近一位同事建议我,如果我使用存储过程来满足我的某些需求,我的解决方案会变得更简洁。我开始阅读它们,它们看起来确实很有前途,但现在我很难让 Hibernate 将从此类存储过程返回的结果映射到 java bean。
这是我要达到的过程:
CREATE OR REPLACE FUNCTION wrong_user_answers(testId INTEGER, userId INTEGER) RETURNS refcursor AS $wrong_user_answers$
DECLARE
ref refcursor;
BEGIN
OPEN ref FOR SELECT ua.*
FROM t_tests as t
JOIN t_user_answers as ua on ua.fk_test_id = t.pk_test_id
WHERE t.pk_test_id = testId and ua.fk_user_id = userId and is_correct(ua) = false;
RETURN ref;
END;
$wrong_user_answers$ LANGUAGE plpgsql;
这里的is_correct(ua)
是我定义的另一个存储过程。我已经在 PGAdmin 中尝试了这个过程,它返回的正是我所期望的 - 包含用户答案的 refcursor。
这是我认为应该全部滚动的代码的 java 部分:
UserAnswerBean
中的附加注释 (@NamedNativeQuery
):
@NamedNativeQueries({
@NamedNativeQuery(name = "getWrongUserAnswers",
query = "select wrong_user_answers(:testId, :userId)",
resultClass = UserAnswerBean.class)
})
@Entity
@Table(name = "t_user_answers")
public class UserAnswerBean {
以及使用该过程的代码:
Query query = getEntityManager().createNamedQuery("getWrongUserAnswers");
query.setParameter("testId", testId);
query.setParameter("userId", userId);
List<UserAnswerBean> answers = query.getResultList();
当收到以下错误的最后一行代码执行尝试时:
org.postgresql.util.PSQLException: The column name pk_user_answer_id was not found in this ResultSet. org.postgresql.jdbc2.AbstractJdbc2ResultSet.findColumn(AbstractJdbc2ResultSet.java:2728) org.postgresql.jdbc2.AbstractJdbc2ResultSet.getInt(AbstractJdbc2ResultSet.java:2589) org.hibernate.type.descriptor.sql.IntegerTypeDescriptor$2.doExtract(IntegerTypeDescriptor.java:74) org.hibernate.type.descriptor.sql.BasicExtractor.extract(BasicExtractor.java:64) org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:267) org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:263) org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:253) org.hibernate.type.AbstractStandardBasicType.hydrate(AbstractStandardBasicType.java:338) org.hibernate.loader.Loader.extractKeysFromResultSet(Loader.java:784) org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:720) org.hibernate.loader.Loader.processResultSet(Loader.java:952)
我不知道如何进行这里,我在互联网上找不到任何有用的资源。所以我认为问题是我返回的是 refcursor,而不是立即返回的选择结果,所以我将存储过程更改为:
CREATE OR REPLACE FUNCTION wrong_user_answers(testId INTEGER, userId INTEGER) RETURNS setof record AS $wrong_user_answers$
SELECT ua.*
FROM t_tests as t
JOIN t_user_answers as ua on ua.fk_test_id = t.pk_test_id
WHERE t.pk_test_id = testId and ua.fk_user_id = userId and is_correct(ua) = false;
$wrong_user_answers$ LANGUAGE sql;
很遗憾,这并没有改变错误。
最后我了解了 @NamedStoredProcedureQuery
注释:
@NamedStoredProcedureQuery(name = "getWrongUserAnswers",
procedureName = "wrong_user_answers", parameters = {
@StoredProcedureParameter(name = "testId", type = Integer.class, mode = ParameterMode.IN),
@StoredProcedureParameter(name = "userId", type = Integer.class, mode = ParameterMode.IN) },
resultClasses = UserAnswerBean.class)
@Entity
@Table(name = "t_user_answers")
public class UserAnswerBean {
使用更改后的 java 代码:
Query query = getEntityManager().createNamedStoredProcedureQuery("getWrongUserAnswers");
query.setParameter("testId", testId);
query.setParameter("userId", userId);
List<UserAnswerBean> answers = query.getResultList();
这也没有解决错误!有人可以帮我弄清楚我做错了什么吗?
最佳答案
最终我能够解决我的问题。
我想我可能在第二种方法上报告了错误的错误。在与 refcursors 的斗争中,我基本上没有任何运气,但是使用 LANGUAGE sql 给了我想要的东西。那就是存储过程:
CREATE OR REPLACE FUNCTION wrong_user_answers(testId INTEGER, userId INTEGER)
RETURNS setof t_user_answers
AS $wrong_user_answers$
SELECT ua.*
FROM t_tests as t
JOIN t_user_answers as ua on ua.fk_test_id = t.pk_test_id
WHERE t.pk_test_id = testId and ua.fk_user_id = userId and is_correct(ua) = false;
$wrong_user_answers$ LANGUAGE sql;
与之前唯一不同的是,我明确指定返回类型为 setof t_user_answers
。注释和 Java 代码与问题中粘贴的完全一样,现在一切都对我有用。
PS:对于那些想知道当我得到的结果是无数据库实体时我更难让一切顺利进行的人,但最后我找到了 @SqlResultSetMapping用 @ConstructorResult 注释classes
子注释来解决问题(虽然很难找到解决方案)。
关于java - 使用 Hibernate 将 PostgreSQL 的 refcursor 映射到 java 实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27669034/