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