【问题标题】:Map refcursor of PostgreSQL to java entity using Hibernate使用 Hibernate 将 PostgreSQL 的 refcursor 映射到 java 实体
【发布时间】:2015-02-24 11:14:41
【问题描述】:

我正在开发一个 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:列名 pk_user_answer_id 在此 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,而不是立即返回 select 的结果,所以我将存储过程更改为:

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();

这也没有改变错误!有人可以帮我弄清楚我做错了什么吗?

【问题讨论】:

  • 如果 Hibernate 能够很好地使用 refcursors,我会感到非常惊讶,除非您执行本机查询 FETCH 语句而不是期望它将它们理解为结果集。
  • 查看我的第二次尝试 - 那里没有使用 refcursor。顺便说一句,我想我在某个地方看到了 hibernate 可以毫无问题地消化 refcursors,可能玩得很聪明并获取它们
  • 它实际上是 PgJDBC 在某些上下文中特殊情况下的 refcursor,通过普通的 jdbc API 将其视为多个结果集。

标签: java sql hibernate postgresql stored-procedures


【解决方案1】:

我终于能够解决我的问题。

我想我可能报告了第二种方法的错误错误。我在与 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 子注释来解决问题(虽然很难找到解决方案)。

【讨论】:

    猜你喜欢
    • 2013-04-05
    • 2013-07-18
    • 1970-01-01
    • 2018-12-10
    • 2015-03-13
    相关资源
    最近更新 更多