将Oracle存储过程结果映射到自定义Java类型(类)
我必须在Oracle(11g)中调用一个存储过程,它使用一个in-OUT参数。此参数是Oracle自定义类型,定义为
CREATE OR REPLACE TYPE "SEPADD"."T_NAPRAVI_NALOG_TEST" IS OBJECT
(
I_INICIJALI varchar2(3) ,
I_STATUS number(1)
)
实际的类型更复杂,但为了更好的可读性,我在这里简化了它。使用这种类型(再次简化)的Oracle过程定义为
CREATE OR REPLACE PROCEDURE "SEPADD"."GETNALOGTESTPROC"(nalog in out T_NAPRAVI_NALOG_TEST )
IS
BEGIN
nalog.I_INICIJALI := 'PC';
nalog.I_STATUS := nalog.I_STATUS + 3;
END;
Oracle自定义类型映射到实现SQLData接口的Java类。(见https://docs.oracle.com/javase/tutorial/jdbc/basics/sqlcustommapping.html#implementing_sqldata)
public class TNapraviNalog implements SQLData{
private int I_STATUS;
private String I_INICIJALI;
private String sql_type = "T_NAPRAVI_NALOG_TEST";
public String getSQLTypeName() {
return sql_type;
}
public int getIStatus(){
return this.I_STATUS;
}
public String getIInicijali(){
return this.I_INICIJALI;
}
public void setIInicijali(String in){
I_INICIJALI = in;
}
public void setIStatus(int st){
I_STATUS = st;
}
public void readSQL(SQLInput stream, String type)
throws SQLException {
sql_type = type;
I_INICIJALI = stream.readString();
I_STATUS = stream.readInt();
}
public void writeSQL(SQLOutput stream)
throws SQLException {
stream.writeString(I_INICIJALI);
stream.writeInt(I_STATUS);
}
}
现在,从我的JDBC代码中,我用以下方式调用Oracle存储过程
Object obj=null;
ResultSet rs=null;
CallableStatement stmt=null;
TNapraviNalog n = null;
try{
sqlQuery = "{call getnalogtestproc(?)}";
Map m = conn.getTypeMap();
m.put("sepadd.T_NAPRAVI_NALOG_TEST", Class.forName("ib.easyorm.db.TNapraviNalog"));//this maps the Java class to the Oracle custom type
conn.setTypeMap(m);
stmt=conn.prepareCall(sqlQuery);
stmt.registerOutParameter(1, Types.STRUCT, "T_NAPRAVI_NALOG_TEST");
stmt.setObject(1, paramValues.get(0) ); //paramValues.get(0) returns an instance of TNapraviNalog class
stmt.execute();
obj = stmt.getObject(1, m);
//obj = stmt.getObject(1,TNapraviNalog.class); this method is not implemented in the JDBC driver
}catch(Exception e){
throw new EasyORMException(e);
}finally{
closeResources(rs,stmt);
}
return obj;
现在的问题是,虽然我可以获得存储过程返回的结果,但结果并没有转换为Java类(TNapraviNalog),所以我必须手动执行。我可以成功 使用TNapraviNalog实例调用Oracle过程(stmt.setObject(1,paramValues.get(0));)但我无法将结果转换为TNapraviNalog。我真的很想 能够拥有像
TNapraviNalog nalog = stmt.getObject(1, m);
但是,此行将导致异常(java.lang.ClassCastException:oracle.sql.STRUCT无法转换为ib.easyorm.db.TNapraviNalog)。 我猜JDBC驱动程序不知道stmt返回的实际类型。因此无法进行转换
有人知道使用普通JDBC或Hibernate是否可以做到这一点吗
编辑:甲骨文页面上的相关代码(慈罕七号的答案中给出了链接)
从可调用语句OUT参数检索SQLData对象
认为您有一个Oracle Labable语句实例OCS,它调用PL/SQL函数GETEnWork。程序将员工编号传递给函数。函数返回相应的Employee对象。要检索此对象,请执行以下操作:
一,。准备OracleCallableStatement以调用GETEMPLOYEE函数,如下所示:
OracleCallableStatement ocs = (OracleCallableStatement)conn.prepareCall("{ ? = call GETEMPLOYEE(?) }");
二,。将empnumber声明为GETEMPLOYEE的输入参数。将SQLData对象注册为OUT参数,类型代码为OracleTypes。结构。然后,运行语句。这可以通过以下方式实现:
ocs.setInt(2, empnumber);
ocs.registerOutParameter(1, OracleTypes.STRUCT, "EMP_OBJECT");
ocs.execute();
三,。使用getObject方法检索employee对象。下面的代码假设有一个类型映射条目将Oracle对象映射到Java类型Employee:
Employee emp = (Employee)ocs.getObject(1); //my comment-->this doesn't seem to work
如果没有类型映射条目,那么getObject将返回一个oracle。sql。结构对象。将输出转换为STRUCT类型,因为getObject方法返回通用java的实例。对象类。具体操作如下:
STRUCT emp = (STRUCT)ocs.getObject(1);
谢谢!
# 1 楼答案
您试图将Struct对象强制转换为
TNapraviNalog
。但是根据Oracle documentation的说法,您应该首先将结构作为java.sql.STRUCT
对象检索,然后将其转换为TNapraviNalog
对象试试这个:
# 2 楼答案
错误似乎出现在这一行:
这是唯一一行使用模式所有者限定
T_NAPRAVI_NALOG_TEST
类型的代码。您可以在另外两个地方引用它,而不使用模式名称如果您是以
SEPADD
用户的身份连接到数据库(看起来是这样),那么可以从此行中删除模式所有者前缀sepadd.
。或者,尝试将上面一行中的模式所有者更改为大写