2017-09-06 16 views
1

私は、ユーザー定義型を含む2つの関連するストアドプロシージャを持っています。最初のオブジェクトはオブジェクトIDを受け取り、それに対応するユーザー定義型のインスタンスを返します。 2つ目は、同じユーザー定義型のインスタンスを受け取り、そのインスタンスで何かを実行します。ユーザー定義型を入力としてストアドプロシージャに渡すにはどうすればよいですか?

私はJava、JDBC、および少しのSpring JDBCを使用しています。私は正常に最初のストアドプロシージャを完了しました。 DBから自分のユーザー定義型のインスタンスを取得できますが、2番目のストアドプロシージャを動作させることはできません。

ここで私がこれまで持っているものの基本的なアウトラインです:

スキーマ(PL/SQL)

create or replace type example_obj as object 
    (ID  NUMBER, 
    NAME VARCHAR2(100)) 

create or replace type example_tab as table of example_obj 

create or replace package 
example as 

procedure getExample 
(p_id  in number, 
p_example out example_tab); 

procedure useExample 
(p_example in example_tab); 

end example; 

エンティティ(ジャワ) - Javaの

public class Example { 
    public BigDecimal ID; 
    public String Name; 
} 
をユーザー定義型を表しますが、

Mapper(Java) - SQL型からJava型に戻ってマップする

public class ExampleMapper extends Example implements SQLData { 
    public static final String SQL_OBJECT_TYPE_NAME = "example_obj"; 
    public static final String SQL_TABLE_TYPE_NAME = "example_tab";  

    @Override 
    public String getSQLTypeName() throws SQLException { 
     return SQL_TABLE_TYPE_NAME; 
    } 

    @Override 
    public void readSQL(SQLInput stream, String typeName) throws SQLException { 
     ID = stream.readBigDecimal(); 
     Name = stream.readString(); 
    } 

    @Override 
    public void writeSQL(SQLOutput stream) throws SQLException { 
     stream.writeBigDecimal(ID); 
     stream.writeString(Name); 
    } 
} 

まずストアドプロシージャ(Javaは) - 私は先に述べたように、そのID

import java.sql.CallableStatement; 
import java.sql.Connection; 
import java.sql.SQLException; 
import org.springframework.jdbc.core.JdbcTemplate; 

public Example getExample(BigDecimal ID) throws SQLException { 
    String query = "begin example.getExample(?, ?); end;"; 
    Connection connection = jdbcTemplate.getDataSource().getConnection(); 
    CallableStatement callableStatement = connection.prepareCall(query); 

    callableStatement.setBigDecimal("p_id", ID); 

    Map<String, Class<?>> typeMap = connection.getTypeMap(); 
    typeMap.put(Example.SQL_OBJECT_TYPE_NAME, ExampleMapper.class); 
    callableStatement.registerOutParameter("p_example", Types.ARRAY, Example.SQL_TABLE_TYPE_NAME); 
    connection.setTypeMap(typeMap); 

    callableStatement.execute(); 

    Array array = (Array)callableStatement.getObject("p_example"); 
    Object[] data = (Object[])array.getArray(); 
    Example example = (Example)data[0]; // It's an ExampleMapper, but I only want Example 
    return example; 
} 

を与え例オブジェクトを取得し、最初のストアドプロシージャが正常に動作しています。データベースから取得されたオブジェクトは、対応するJavaオブジェクトに自動的にマップされます。次の手順では、このユーザー定義型のインスタンスを受け入れるストアドプロシージャを呼び出すことができます。手順(Java)のストアド

秒 - 例オブジェクトを使用 - 不完全

public void useExample(Example example) throws SQLException { 
    String query = "begin example.useExample(?); end;"; 
    Connection connection = jdbcTemplate.getDataSource().getConnection(); 
    CallableStatement callableStatement = connection.prepareCall(query); 

    // Is this required (as per getExample())? 
    Map<String, Class<?>> typeMap = connection.getTypeMap(); 
    typeMap.put(Example.SQL_OBJECT_TYPE_NAME, ExampleMapper.class); 
    connection.setTypeMap(typeMap); 

    /*** 
    *** What goes here to pass the object in as a parameter? 
    ***/ 
    callableStatement.setObject("p_example", ???); 

    callableStatement.execute(); 
} 

答えて

0

の周りいじくるの公平なビットの後、私は、ソリューションを開発することができました。いくつかの観察:

  • Web上でこれを行う方法についてはあまり書かれていません。
  • 入力のようなユーザー定義型を使用することは十分サポートされていないようです。
  • Structを使用しなければなりませんでした。出力には配列のみが使用されていたため、直感的でした。
  • SQLDataインターフェイスが使用されていません。 writeSQL()は、構造体を手動で構築しなければならないとわかったので、決して呼び出されませんでした。出力をマッピングするときにはreadSQL()が呼び出されます。
  • 私は配列作成のためにDB固有のコードを使用しなければなりませんでした。私の場合、これはOracleクラスを意味していました。

私は間違ったやり方をしている可能性がありますので、私の解説についてのコメントを歓迎します。

public void useExample(Example example) throws SQLException { 
    String query = "begin example.useExample(?); end;"; 
    Connection connection = jdbcTemplate.getDataSource().getConnection(); 
    CallableStatement callableStatement = connection.prepareCall(query); 

    Map<String, Class<?>> typeMap = connection.getTypeMap(); 
    typeMap.put(Example.SQL_OBJECT_TYPE_NAME, ExampleMapper.class); 
    connection.setTypeMap(typeMap); 

    // Manually convert the example object into an SQL type. 
    Object[] exampleAttributes = new Object[]{example.ID, example.Name}; 
    Struct struct = connection.createStruct(type.getObjectType(), exampleAttributes); 

    // Build the array using Oracle specific code. 
    DelegatingConnection<OracleConnection> delegatingConnection = (DelegatingConnection<OracleConnection>) new DelegatingConnection(connection); 
    OracleConnection oracleConnection = (OracleConnection) delegatingConnection.getInnermostDelegate(); 
    Object[] data = new Object[]{struct}; 
    Array array oracleConnection.createOracleArray(Example.SQL_TABLE_TYPE_NAME, data); 

    // Set the input value (finally). 
    callableStatement.setObject("p_example", array); 

    callableStatement.execute(); 
} 
関連する問題