java - 使用 Hibernate 将 PostgreSQL 的 refcursor 映射到 java 实体

标签 java sql hibernate postgresql stored-procedures

我正在开发一个 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/

相关文章:

java - 使用 Lucene 库指定文档字段

java - 两次读取输入流而不将其存储在内存中

java - JSOUP 中的用户代理?

php - 清理数据是否消除了 SQL 注入(inject)的可能性?

java - 以编程方式定义 Spring DataSource 导致 ClassNotFoundException

java - 将 Tomcat 5.5 输出写入 Tomcat 的日志文件之一

python - 如何使用peewee limit()?

java - 如何在 java 和 hibernate 中存储精确的精度值?

java - 为每个单元测试重建 Hibernate sessionFactory(使用 spring 框架)

php - WHERE 子句中的 NULL