2016-04-29 15 views
1

単一のIN OUTパラメータを使用するOracle(11g)のストアドプロシージャを呼び出す必要があります。このパラメータは、Oracleストアドプロシージャの結果をカスタムJavaタイプ(クラス)にマッピング

CREATE OR REPLACE TYPE "SEPADD"."T_NAPRAVI_NALOG_TEST" IS OBJECT 
(
    I_INICIJALI    varchar2(3) ,   
    I_STATUS     number(1)   
) 

実際の型は、より複雑ですが、私は読みやすくするためにここにそれを簡素化として定義されているOracleのカスタム型です。このタイプ(再度簡略化された)を使用して、Oracle手順は

​​

として定義されているOracleカスタムタイプは、SQLDataインタフェースを実装するJavaクラスにマッピングされます。

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コードから、私は次のよう今

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; 

にOracleのストアドプロシージャを呼び出す(https://docs.oracle.com/javase/tutorial/jdbc/basics/sqlcustommapping.html#implementing_sqldataを参照)、問題がある、つまり私は返された結果を得ることができますしながら、ストアドプロシージャは、結果はJavaクラス(TNapraviNalog)に変換されないので、私は手動で行う必要があります。私は正常に TNapraviNalog(stmt.setObject(1、paramValues.get(0));)のインスタンスでOracleプロシージャを呼び出すことができますが、TNapraviNalogに変換された結果を得ることができません。 oracle.sql.STRUCTがib.easyorm.dbにキャストすることはできません。私は本当にしかし、この行は例外(とjava.lang.ClassCastExceptionが発生します が

TNapraviNalog nalog = stmt.getObject(1, m); 

のようなものを持ってできるようにしたいと思います。 TNapraviNalog)。 私は、JDBCドライバがstmt.getObject(1、m)によって返された実際の型を認識しておらず、変換を行うことができないと推測しています。

プレーンなJDBCとHibernateのどちらを使ってもこれを行うことができますか?

EDIT:(ジハン7の答えで与えられたリンク)のOracleページから該当するコード

コール可能文OUT

は、あなたがするOracleCallableStatementインスタンスを持って考えてみましょう。パラメータから取得するSQLDataオブジェクト

、OCS PL/SQLファンクションGETEMPLOYEEをコールします。プログラムは従業員番号を関数に渡します。この関数は、対応するEmployeeオブジェクトを返します。

1.Prepare OracleCallableStatementを次のように、GETEMPLOYEE関数を呼び出す:

OracleCallableStatement ocs = (OracleCallableStatement)conn.prepareCall("{ ? = call GETEMPLOYEE(?) }"); 

を2.Declare EMPNUMBER GETEMPLOYEEへの入力パラメータとして使用すると、次の操作を実行し、このオブジェクトを取得するには。タイプ・コードOracleTypes.STRUCTを使用して、OUTパラメータとしてSQLDataオブジェクトを登録します。次に、ステートメントを実行します。これは、次のようにして実行できます。

ocs.setInt(2, empnumber); 
ocs.registerOutParameter(1, OracleTypes.STRUCT, "EMP_OBJECT"); 
ocs.execute(); 

3. getObjectメソッドを使用して従業員オブジェクトを取得します。

Employee emp = (Employee)ocs.getObject(1); //my comment-->this doesn't seem to work 

何の型マップ・エントリが存在しない場合は、getObjectメソッドはoracle.sql.STRUCTオブジェクトを返します:次のコードは、Java型の従業員へのOracleオブジェクトをマッピングするための型マップ・エントリがあることを前提としています。getObjectメソッドが汎用java.lang.Objectクラスのインスタンスを返すため、出力をSTRUCT型にキャストします。これは、次のように行われます。

STRUCT emp = (STRUCT)ocs.getObject(1); 

はあなたがTNapraviNalogにあなたのStructオブジェクトをキャストしようとするあなたに

答えて

1

は、この行にあるように表示されます。

 m.put("sepadd.T_NAPRAVI_NALOG_TEST", Class.forName("ib.easyorm.db.TNapraviNalog"));//this maps the Java class to the Oracle custom type 

これは、スキーマの所有者とあなたのT_NAPRAVI_NALOG_TESTタイプを修飾している唯一のラインです。スキーマ名なしで他の2つの場所で参照します。

データベースにSEPADDというユーザーとして接続している場合は、この行からスキーマ所有者接頭辞sepadd.を削除できます。あるいは、上記の行のスキーマ所有者を大文字に変更してみてください。

+0

私はどこにでもスキーマ名を追加しようとしましたが、何の違いもありませんでした。スキーマ名を明示的に追加することは、あなたが気付いたとおりにユーザー名が実際にsepaddであっても、(ユーザー名に関係なく)間違いではありません。スキーマ名の削除は役に立ちません。私はTNapraviNalogのインスタンスでプロシージャを正常に呼び出すことができるので、マッピングはOKです。問題は、JDBCドライバが常に結果をSTRUCTとして返すことです。結果をTNapraviNalogオブジェクトに変換しようとはしません。 –

+0

@dsp_user:それは奇妙です。上の行のスキーマ名を大文字に変更するだけでした。スキーマ名を削除することもできました。私はWindows 10 x64上でOracle 11g XEバージョン11.2.0.2.0を使用しています.4つの異なるOracle JDBCドライバJARを使用してコードを実行しました。ojdbc14.jarバージョン10.2.0.5 .0、ojdbc5.jarバージョン11.2.0.4.0、ojdbc6.jarバージョン11.2.0.2.0およびojdbc7.jarバージョン12.1.0.2.0。 –

+0

「稼働させる」ということは、正確にはどういう意味ですか?結果をTNapraviNalog型として取得しますか?私のコードは動作しますが、結果はTNapraviNalogに変換されず、代わりにstmt.getObject(1、m)から常にSTRUCTオブジェクトを取得します。確かに、私は返されたオブジェクトを解析し、ちょうど良い値を得ることができます。 –

2

ありがとうございます。しかし、Oracle documentationによれば、まず構造体をjava.sql.STRUCTオブジェクトとして取得し、それをTNapraviNalogオブジェクトに変換する必要があります。

この試してみてください。エラー

java.sql.Struct jdbcStruct = (java.sql.Struct)stmt.getObject(1, m); 
+0

型マップが定義されていない場合は、oracle.sql.STRUCT(java.sql.Structのスーパークラス)が戻されます。とにかく、Struct(またはSTRUCT)をカスタム型にキャストすることはできません(私はそれを試しました) –

+0

もちろん、結果はoracle.sql.STRUCT(java.sql.Structのサブクラス)として取得できますが、 TNapraviNalogにキャストできません。 –

+0

_generic_ javaクラスを定義して、そのクラスに 'oracle.sql.STRUCT'をキャストして、_generic_クラスを' TNapraviNalog'クラスにキャストしようとするといいでしょうか? –

関連する問題