4

Oracle プロシージャ コールの out パラメータをオブジェクトにキャストしようとしています。私が理解しているように、メソッドにキャスト方法を伝えるマップを定義する必要があるため、機能しません。マップが空の場合、または正しく埋められていない場合、デフォルトで STRUCT タイプの Objekt になります。これは私の場合は間違っています。

問題を説明するサンプルを作成しました。

-- Procedure in database
PROCEDURE myprocedure (
inputParam                IN       VARCHAR2 (4),
outputOne                 OUT outputOneSQLType
outputTwo                 OUT outputTwoSQLType);

-- inside of a package
inside a package mypackage

-- first type
create or replace
TYPE outputOneSQLType IS TABLE OF tableOneExample

-- table of type
create or replace
TYPE tableOneExample AS OBJECT (
      somethingOne                 VARCHAR2 (4)
     ,somethingTwo        NUMBER (12)
)

//java from here

import oracle.jdbc.OracleCallableStatement;
import oracle.jdbc.OracleTypes;
import oracle.jdbc.oracore.OracleTypeADT;
import oracle.sql.STRUCT;
...
oracle.jdbc.driver.OracleConnection oracleConn = (oracle.jdbc.driver.OracleConnection) con.getMetaData().getConnection();
final OracleCallableStatement storedProc = (OracleCallableStatement)oracleConn.prepareCall("{call mypackage.myprocedure("+
                ":inputParam, :outputOne, :outputTwo)}");

storedProc.setString("inputParam", "SomeValue");

storedProc.registerOutParameter("outputOne",  OracleTypes.STRUCT, "OUTPUTONESQLTYPE");
storedProc.registerOutParameter("outputTwo",  OracleTypes.STRUCT, "OUTPUTTWOSQLTYPE");

storedProc.execute();

//So far so good

//now I am lost - I need to define the map to get the object? 
//What should be inside the map?
Hashtable newMap = new Hashtable();

newMap.put("outputOneSQLType", ?????.class);

//If the map is empty, it defaults to STRUCT...
final STRUCT myObject =  (STRUCT)storedProc.getObject("somethingOne",newMap);
// myObject.getBytes() gives me an object... but I cannot cast it to anything

不完全なマップのため、次のようなものは使用できません。

final MyClass myObject =  (MyClass)storedProc.getObject("somethingOne",newMap);   

マップを埋めるにはどうすればよいですか?

編集 1

Oracle データベースのエントリは変更できません。私はそれらを使用することを許可されています。そのため

stmt.registerOutParameter(2, java.sql.Types.ARRAY, "OUTPUTONESQLTYPE"); 

動作しません。「OracleTypes.STRUCT」を使用しないとすぐに例外がスローされるためです。outputOneSQLType の中に "OracleTypeCOLLECTION" 型のオブジェクトがあるようです

やってみると

 Hashtable newMap = new Hashtable();
newMap.put("outputOneSQLType",OracleTypeCOLLECTION.class);
final OracleTypeCOLLECTION myObject =  (OracleTypeCOLLECTION)storedProc.getObject("somethingOne",newMap);

例外があります:InstantiationException: oracle.jdbc.oracore.OracleTypeCOLLECTION

@DazzL: SQLDATA インターフェイスを定義してみます。多分それは解決策になるでしょう

解決

  1. 準備されたステートメントは、「begin package.procedure(...); end;」のようなものにする必要があります。NOT "{call package.procedure ( ...)})
  2. SQLData インターフェイスが必要です。

@DazzL: あなたが支配する! どうも。

4

1 に答える 1

6

これをマップするには、sqldataオブジェクトを定義する必要があります。

ドキュメント:http ://docs.oracle.com/cd/E11882_01/java.112/e16548/oraarr.htm#JJDBC28574

例えば:

SQL> create or replace TYPE tableOneExample AS OBJECT (
  2        somethingOne                 VARCHAR2 (4)
  3       ,somethingTwo        NUMBER (12)
  4  );
  5  /

Type created.

SQL> create or replace TYPE outputOneSQLType IS TABLE OF tableOneExample;
  2  /

Type created.

SQL>
SQL> create or replace PROCEDURE myprocedure (
  2  inputParam                IN       VARCHAR2,
  3  outputOne                 OUT outputOneSQLType)
  4  as
  5  begin
  6  outputOne  := outputOneSQLType(tableOneExample('a', 1), tableOneExample('b', 2));
  7  end;
  8  /

Procedure created.

次に、SQLDATAインターフェースを定義します。

import java.sql.*;

public class TestArr implements SQLData
 {
  private String sql_type;

  public String attrOne;
  public int    attrTwo;

  public TestArr() 
  { 
  }
  public TestArr (String sql_type, String attrOne, int attrTwo)
  {
    this.sql_type = sql_type;
    this.attrOne = attrOne;
    this.attrTwo = attrTwo;
   }

  // define a get method to return the SQL type of the object
  public String getSQLTypeName() throws SQLException
  { 
    return sql_type; 
  } 

  // define the required readSQL() method 
  public void readSQL(SQLInput stream, String typeName)
    throws SQLException
  {
    sql_type = typeName;

    attrOne = stream.readString();
    attrTwo = stream.readInt();
  }  
  // define the required writeSQL() method 
  public void writeSQL(SQLOutput stream)
    throws SQLException
  { 
    stream.writeString(attrOne);
    stream.writeInt(attrTwo);
  }
}

ストリームの書き込み/読み取りの入力と順序がOracleタイプと同じであることを確認してください。不整合があると、内部表現エラーが発生します。

次に、メインクラスで、これを次のようにマップします。

CallableStatement stmt = conn.prepareCall("begin myprocedure(?,?); end;");
stmt.setString(1, "foo");
stmt.registerOutParameter(2, java.sql.Types.ARRAY, "OUTPUTONESQLTYPE"); // YOUR ARRAY TYPE (TO MATCH THE API OUTPUT), NOT OBJECT
stmt.execute();
Array arr = stmt.getArray (2);
Map map = conn.getTypeMap();
map.put("TABLEONEEXAMPLE", Class.forName("TestArr")); // YOUR OBJECT TYPE, NOT ARRAY.
Object[] values = (Object[]) arr.getArray();
for (int i=0; i < values.length; i++)
{
  TestArr a = (TestArr)values[i];
  System.out.println("somethingOne: " + a.attrOne);
  System.out.println("somethingTwo: " + a.attrTwo);
}

結果ビエン:

M:\Documents\Sample Code\1>javac TestArr.java

M:\Documents\Sample Code\1>javac ArrayTest.java
Note: ArrayTest.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.

M:\Documents\Sample Code\SQLComplexArray>java ArrayTest
Opening Oracle connection...done.
somethingOne: a
somethingTwo: 1
somethingOne: b
somethingTwo: 2
于 2012-12-10T14:10:33.417 に答える