2012-10-04 42 views
7

He estado buscando en Google por un tiempo y parece que no puedo encontrar ninguna respuesta real.Cómo pasar la lista de objetos de Java a procedimientos almacenados de Oracle utilizando MyBatis?

Tengo un procedimiento almacenado de Oracle que tiene una serie de parámetros que tienen un tipo que es la tabla de la tabla rowtype. Así, por ejemplo:

declarado de la pacakge:

TYPE param1_type_t IS TABLE OF table1%ROWTYPE; 
TYPE param2_type_t IS TABLE OF table2%ROWTYPE; 
TYPE param3_type_t IS TABLE OF table3%ROWTYPE; 

Procedimiento Oracle:

PROCEDURE my_proc 
(
    parameter1 IN param1_type_t, 
    parameter2 IN param2_type_t, 
    parameter3 IN param3_type_t 
) 

En el lado java, tengo 3 correspondientes listas de objetos que representan cada una de las parámetros que se rellenan en Java. ¿Es posible llamar al procedimiento Oracle utilizando MyBatis en este escenario?

<update id="callOracleSP" statementType="CALLABLE"> 
    {CALL my_proc(#{param1, mode=IN}, 
        #{param2, mode=IN}, 
        #{param3, mode=IN} 
       ) 
    } 
</update> 

los objetos mismos son VOs simples con propiedades String e Integer y sus respectivos captadores y definidores.

No estoy seguro de cómo proceder. ¿Debo de alguna manera mapear las listas de objetos de Java a los tipos de Oracle?

Gracias de antemano.

Respuesta

7

No sé si ya lo hace o no, pero necesitará objetos de Oracle definidos.

CREATE OR REPLACE TYPE SCHEMA."YOUR_OBJECT" AS OBJECT 
(
    field_one varchar2(50), 
    field_two varchar2(100) 
); 
/
CREATE OR REPLACE TYPE SCHEMA."YOUR_OBJECT_ARRAY" AS TABLE OF YOUR_OBJECT; 
/

A continuación, puede escribir controladores de tipos para asignar los objetos de Java a los objetos de Oracle.

import oracle.sql.ARRAY; 
import oracle.sql.ArrayDescriptor; 
import oracle.sql.STRUCT; 
import oracle.sql.StructDescriptor; 
.... 
public class YourTypeHandler implements TypeHandler 
{ 
.... 
    public void setParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException 
    { 
     List<YourObject> objects = (List<YourObject>) parameter; 

     StructDescriptor structDescriptor = StructDescriptor.createDescriptor("YOUR_OBJECT", ps.getConnection()); 

     STRUCT[] structs = new STRUCT[objects.size()]; 
     for (int index = 0; index < objects.size(); index++) 
     { 
      YourObject pack = packs.get(index); 
      Object[] params = new Object[2]; 
      params[0] = pack.getFieldOne(); 
      params[1] = pack.getFieldTwo(); 
      STRUCT struct = new STRUCT(structDescriptor, ps.getConnection(), params); 
      structs[index] = struct; 
     } 

     ArrayDescriptor desc = ArrayDescriptor.createDescriptor("YOUR_OBJECT_ARRAY", ps.getConnection()); 
     ARRAY oracleArray = new ARRAY(desc, ps.getConnection(), structs); 
     ps.setArray(i, oracleArray); 
    } 
} 

continuación, se invoca el procedimiento,

respuesta de
call your_proc 
(
#{yourObjects, javaType=Object, jdbcType=ARRAY, jdbcTypeName=YOUR_OBJECT_ARRAY, mode=IN, typeHandler=YourObjectArrayTypeHandler} 
) 
+0

no puede encontrar clase/jar para TypeHandler. ya tiene ojdbc6.jar – aishu

0

Andy Pryor es muy bueno lo probé y realmente funciona. Pero tiene un error en TypeHandler:

call your_proc 
(
#{yourObjects, javaType=Object, jdbcType=ARRAY, jdbcTypeName=YOUR_OBJECT_ARRAY, mode=IN, typeHandler=YourObjectArrayTypeHandler} 
) 

debería ser:

call your_proc 
(
#{yourObjects, javaType=Object, jdbcType=ARRAY, jdbcTypeName=YOUR_OBJECT_ARRAY, mode=IN, typeHandler=YourTypeHandler} 
) 

El TypeHandler tiene un error así: (no hay "paquetes" y hay una cierta diferencia en los parámetros del método de mi versión)

@Override 
public void setParameter(PreparedStatement ps, int i, Object parameter, String arg3) throws SQLException { 
    List<YourObject> objects = (List<YourObject>) parameter; 

    StructDescriptor structDescriptor = StructDescriptor.createDescriptor("YOUR_OBJECT", ps.getConnection()); 

    STRUCT[] structs = new STRUCT[objects.size()]; 
    for (int index = 0; index < objects.size(); index++) 
    { 
     YourObject pack = objects.get(index); 
     Object[] params = new Object[2]; 
     params[0] = pack.getFieldOne(); 
     params[1] = pack.getFieldTwo(); 
     STRUCT struct = new STRUCT(structDescriptor, ps.getConnection(), params); 
     structs[index] = struct; 
    } 

    ArrayDescriptor desc = ArrayDescriptor.createDescriptor("YOUR_OBJECT_ARRAY", ps.getConnection()); 
    ARRAY oracleArray = new ARRAY(desc, ps.getConnection(), structs); 
    ps.setArray(i, oracleArray); 
} 

Y aquí es un ejemplo de mapeo XML:

<parameterMap id="updateHierPersonAssignMap" class="java.util.Map" >      
    <parameter property="p_array" jdbcType="ARRAY" javaType="Object" mode="IN" typeHandler="com.aamtech.ria.model.domain.typehandler.YourTypeHandler"/> 
    </parameterMap> 
    <procedure id="updateHierPersonAssign" parameterMap="updateHierPersonAssignMap" > 
    <![CDATA[ 
     { call ria_am_util_pkg.j_update_hier_person_assign(?) } 
    ]]> 
    </procedure> 

Y aquí es cómo se puede llamar desde el DAO:

public void update(List array) { 
    Map<String, Object> queryParams = new HashMap<String, Object>(); 
    queryParams.put("p_array", array); 
    try { 
     client.update("HashMapResult.updateHierPersonAssign", queryParams); 
    } catch (SQLException e) { 
    } 
} 

Y mi procedimiento se parece a esto (sólo inserta una fila en una tabla de prueba):

Procedure j_update_hier_person_assign (p_array IN YOUR_OBJECT_ARRAY) is 
    begin 
    FOR i IN 1..p_array.count LOOP 
     --dbms_output.put_line(); 
     insert into test (a) values (p_array(i).field_one); 
    END LOOP; 
    end; 
Cuestiones relacionadas