StoredProcedureQuery getResultList()不返回数据键(列标题)

时间:2019-03-25 19:38:06

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

我正在尝试从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();
  }
}

2 个答案:

答案 0 :(得分:0)

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

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

答案 1 :(得分:0)

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

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

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

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

在蟾蜍中运行时,您应该可以创建输出类    包演示;

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