【问题标题】:StoredProcedureQuery getResultList() does not return the data keys (column headers)StoredProcedureQuery getResultList() 不返回数据键(列标题)
【发布时间】:2019-03-25 19:38:06
【问题描述】:

我正在尝试从 Oracle 数据库上的存储过程中获取结果。这些过程是数据库包的一部分,所以我无法看到这些过程的实现。因此,除非我使用有效输入执行程序,否则我看不到返回的列标题。我正在使用 StoredProcedureQuery 在我的代码中执行这些过程。问题是,在将结果映射到 POJO 时,我必须依赖返回的列的顺序来映射 POJO 字段。
我知道一种解决方案是定义 SQLResultSetMappings。但是由于我不知道查询了哪些表来获取结果,所以我无法将其映射到实体。是否有另一种方法可以返回带有列标题的结果? 这是我的程序声明:

@NamedStoredProcedureQuery(
   name = "myStoredProcedure",
   procedureName = "MYUSER.PKG_MY_PACKAGE.MY_STORED_PROCEDURE",
   parameters = {
      @StoredProcedureParameter(mode = ParameterMode.IN, type = Long.class, name = "iMyNumber"),
      @StoredProcedureParameter(mode = ParameterMode.OUT, type = Long.class, name = "oRetVal"),
      @StoredProcedureParameter(mode = ParameterMode.OUT, type = String.class, name = "oRetTxt"),
      @StoredProcedureParameter(mode = ParameterMode.REF_CURSOR, type = void.class, name = "oRetCsr"),
   }
)

这是我的 DAO 代码:

public List<MyQueryResultModel> getMyQueryResults(Long myNum) {
  StoredProcedureQuery query = this.entityManager.createNamedStoredProcedureQuery("myStoredProcedure");
  query.setParameter("iMyNumber", myNum);
  try {
    List<Object[]> results = query.getResultList();
    List<MyQueryResultModel> myQueryResults = new ArrayList<>();
    for (Object[] result : results) {
      MyQueryResultModel myQueryResult = new MyQueryResultModel();
      myQueryResult.setId(objectToString(result[0]));
      myQueryResult.setName(objectToString(result[1]));
      myQueryResult.setDetails(objectToString(result[2]));
      myQueryResult.setAlias(objectToString(result[3]));
      myQueryResult.setDescription(objectToString(result[4]));
      myQueryResult.setAbbreviation(objectToString(result[6]));

      myQueryResults.add(myQueryResult);
    }
    return myQueryResults;
  } catch (Exception e) {
    return null;
  } finally {
    query.unwrap(ProcedureOutputs.class).release();
  }
}

【问题讨论】:

    标签: hibernate spring-boot jpa stored-procedures spring-data-jpa


    【解决方案1】:

    只要您的类是@Entityexample,您就可以使用resultClasses = { MyQueryResultModel.class }, 自行处理对象映射。

    如果不是,您可以使用resultSetMapping 传递您的SQLResultMapping 这是usage 的示例,我认为您不需要提前知道查询将命中的表,您只需要知道列名,可以在 SQL 查询中定义。如果不是,您可以在最后一条语句中使用别名来定义它们。

    【讨论】:

      【解决方案2】:

      @StoredProcedureParameter(mode = ParameterMode.REF_CURSOR, type = void.class, name = "oRetCsr"),

      这是 Oracle 存储过程。因此,您可以在 Toad 或 PL/SQL 查询运行中运行它并查看结果集中的所有输出列。然后在结果集中使用这些列名 示例有 System.out.println (rset.getString ("ENAME"));从光标获取 ENAME 所以映射你的 in 类型 Out 类型参数并检查数据的 refcursor,你可以从 columname 获取数据。

      如何将参数传递给 PL/SQL 中的过程和函数? 在 PL/SQL 中,我们可以通过三种方式将参数传递给过程和函数。

      1) IN 类型参数:这些类型的参数用于向存储过程发送值。 2) OUT 类型参数:这些类型的参数用于从存储过程中获取值。这类似于函数中的返回类型。 3) IN OUT 参数:这些类型的参数用于发送值和从存储过程中获取值。

      当您在 toad 中运行时,您应该能够创建输出类 包演示;

      import javax.persistence.Entity;
      import javax.persistence.GeneratedValue;
      import javax.persistence.Id;
      import javax.persistence.NamedStoredProcedureQueries;
      import javax.persistence.NamedStoredProcedureQuery;
      import javax.persistence.ParameterMode;
      import javax.persistence.StoredProcedureParameter;
      
      @NamedStoredProcedureQueries({ //
      @NamedStoredProcedureQuery(name = "Role.findRolesViaProcedure", procedureName = "collect_roles",
              resultClasses = Role.class, parameters = { //
              @StoredProcedureParameter(name = "role_list_o", mode = ParameterMode.REF_CURSOR, type = void.class) }) //
      })
      @Entity
      public class Role {
      
          @Id @GeneratedValue//
          private Long id;
      
          private String name;
      
          public Long getId() {
              return id;
          }
      
          public void setId(Long id) {
              this.id = id;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      }
      
      
       RoleRepository.java
      package demo;
      
      import java.io.Serializable;
      import java.util.List;
      
      import org.springframework.data.jpa.repository.query.Procedure;
      import org.springframework.data.repository.CrudRepository;
      
      interface RoleRepository extends CrudRepository<Role, Serializable> {
      
          @Procedure
          List<Role> findRolesViaProcedure();
      }
       schema.sql
      CREATE TABLE "ROLE" 
         (    "ID" NUMBER(10,0), 
          "NAME" VARCHAR2(255 CHAR)
         );
      
      Insert into TRAINING.ROLE (ID,NAME) values ('1','A');
      Insert into TRAINING.ROLE (ID,NAME) values ('2','B');
      Insert into TRAINING.ROLE (ID,NAME) values ('3','C');
      
      
      CREATE or replace PROCEDURE collect_roles (role_list_o OUT SYS_REFCURSOR) AS
           BEGIN 
             OPEN role_list_o FOR SELECT id, name FROM role; 
           END;
      
       SpringDataJpaBugDatajpa652Application.java
      package demo;
      
      import javax.persistence.EntityManagerFactory;
      import javax.sql.DataSource;
      
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;
      import org.springframework.context.annotation.Bean;
      import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
      import org.springframework.orm.jpa.vendor.Database;
      import org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter;
      
      @SpringBootApplication
      public class SpringDataJpaBugDatajpa652Application {
      
          public static void main(String[] args) {
              SpringApplication.run(SpringDataJpaBugDatajpa652Application.class, args);
          }
      
          @Bean
          public EntityManagerFactory entityManagerFactory(LocalContainerEntityManagerFactoryBean bean) {
              return bean.getObject();
          }
      
          @Bean
          public LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean(DataSource dataSource) {
      
              LocalContainerEntityManagerFactoryBean bean = new LocalContainerEntityManagerFactoryBean();
      
              bean.setLoadTimeWeaver(new org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver());
              bean.setDataSource(dataSource);
              EclipseLinkJpaVendorAdapter jva = new EclipseLinkJpaVendorAdapter();
              jva.setDatabase(Database.ORACLE);
              jva.setShowSql(true);
              bean.setJpaVendorAdapter(jva);
      
              return bean;
          }
      }
       SpringDataJpaBugDatajpa652ApplicationTests.java
      package demo;
      
      import java.util.List;
      
      import javax.sql.DataSource;
      
      import org.junit.Test;
      import org.junit.runner.RunWith;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.boot.test.SpringApplicationConfiguration;
      import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
      
      @RunWith(SpringJUnit4ClassRunner.class)
      @SpringApplicationConfiguration(classes = SpringDataJpaBugDatajpa652Application.class)
      public class SpringDataJpaBugDatajpa652ApplicationTests {
      
          @Autowired DataSource dataSource;
      
          @Autowired RoleRepository roleRepository;
      
          @Test
          public void contextLoads() {
      
              System.out.println(dataSource);
      
              List<Role> roles = roleRepository.findRolesViaProcedure();
      
              System.out.println(roles);
          }
      }
      

      https://gist.github.com/thomasdarimont/129bc15d0ccc459610c2

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-11-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-07-17
        • 1970-01-01
        • 2021-09-25
        相关资源
        最近更新 更多