Tabla de Contenidos

Obtener una Colección mediante JDBC

Para mapear objetos colección mediante JDBC, vamos a mostrar el ejemplo utilizado para solucionar al error ORA-01000 en /*Consulta de Notas de Selectividad del 2015*/.

Código PL/SQL

Lo primero que tenemos que definir es el tipo que va a contener los datos (representa la fila de una tabla), en este caso se utiliza un Object como base, y se declara fuera del paquete PL/SQL. Recordad que tenemos que darle el permiso EXECUTE al usuario JV_ asociado con la aplicación WEB.

Este elemento se puede obviar si utilizamos un table_name%ROWTYPE.

CREATE OR REPLACE TYPE ACCESO.R_NOTAS_PARTE_GENERAL AS Object(
    dni             VARCHAR2(8),
    letra           VARCHAR2(1),
    año             NUMBER,
    conv            VARCHAR2(1),
    cod_tipo_acceso VARCHAR2(1),
    cod_materia     VARCHAR2(10),
    num_correccion  NUMBER,
    nota            NUMBER,
    nulo1           VARCHAR2(1),
    nulo2           VARCHAR2(1),
    des_materia     VARCHAR2(40)
);
 
GRANT EXECUTE ON ACCESO.R_NOTAS_PARTE_GENERAL TO JV_ACCESO;

Ahora creamos el tipo que va a representar la tabla (sería la colección de objetos) basado en el tipo anterior, fuera del paquete PL/SQL y darle el permiso EXECUTE al usuario JV_ asociado con la aplicación WEB.

CREATE OR REPLACE TYPE ACCESO.T_NOTAS_PARTE_GENERAL IS TABLE OF ACCESO.R_NOTAS_PARTE_GENERAL;
 
 
GRANT EXECUTE ON ACCESO.T_NOTAS_PARTE_GENERAL TO JV_ACCESO;

A continuación, tenemos el código de la función.

FUNCTION f_notas_parte_general(p_anyo IN NUMBER, p_conv IN VARCHAR2,p_tipo_acceso IN VARCHAR2,p_dni IN VARCHAR2, p_letra IN VARCHAR2) RETURN ACCESO.T_NOTAS_PARTE_GENERAL IS
 
     i NUMBER(2) := 0;    
     t_notas ACCESO.T_NOTAS_PARTE_GENERAL := ACCESO.T_NOTAS_PARTE_GENERAL();
 
     Cursor c_notas_general IS
         SELECT P.dni, P.letra, P.año, P.conv, P.cod_tipo_acceso, P.cod_materia, P.num_correccion, P.nota, mp.des_materia
           FROM TABLA1 P, TABLA2 mp
          WHERE cond1 = ? AND cond2 = ? ;
 
     BEGIN
         FOR c IN c_notas_general Loop
                i := i + 1;
                dbms_output.put_line(i);              
                t_notas.Extend;
                t_notas(i) := ACCESO.R_NOTAS_PARTE_GENERAL( c.dni, c.letra, c.año, c.conv, c.cod_tipo_acceso, c.cod_materia,  c.num_correccion, c.nota, NULL, NULL,  c.des_materia);    
         END Loop;       
        RETURN t_notas;
END f_notas_parte_general;

Código JAVA

Los pasos serian los siguientes:

1- Configuramos la cadena de la llamada PL/SQL.
2- Obtenemos la meta información del tipo PL/SQL que contiene los datos.
3- Indicamos que el resultado es de tipo ARRAY.
4- Obtenemos el ARRAY JDBC.
5- Obtenemos el array de Objects Java.
6- Los objetos del ARRAY JDBC son STRUCT.
7- Obtenemos los atributos del STRUCT.
8- Iteramos sobre los atributos del STRUCT, para crear el objeto que utilizamos en la aplicación.
9- Devolvemos la lista de objetos, con la representación de la aplicación

   /**
     * Devuelve las notas de la parte general para un año, convocatoria, tipo de acceso y usuario
     * SE OBTIENEN CON UN ARRAY DE OBJETOS ORACLE
     * FUNCIONA COMO ESTÁ
     * @author javierbl
     * @return 1 si la clave es correcta, 0 en caso contrario
     */
    public List<NotaMateria> funNotasParteGeneral(short anyo, String conv, String tipo_acceso, String dni, String letra)
    {
        Connection con = null;
        CallableStatement cs = null;
        ResultSet rs = null;
        List<NotaMateria> al = new ArrayList<NotaMateria>();
 
        try
        {        
            Map<String, String> logParams = new LinkedHashMap<String, String>(); 
            String consulta = "MI_PAQUETE.f_mi_funcion";
            logParams.put("p_año", anyo+"");
            logParams.put("p_conv", conv);
            logParams.put("p_tipo_acceso", tipo_acceso);
            logParams.put("p_dni", dni);
            logParams.put("p_letra", letra);       
            this.getLog().info("Ejecutamos el método funNotasParteGeneral, consulta [%0] - paramtreos [%1]", consulta, logParams) ;  
 
            // 1- Configuramos la cadena de la llamada PL/SQL.
            String llamada = new String("{? = call ACCESO.MI_PAQUETE.f_mi_funcion(?,?,?,?,?)}");
            con = this.dataSource.getConnection();
 
            // 2- Obtenemos la meta información del tipo PL/SQL que contiene los datos
            StructDescriptor stDesc = StructDescriptor.createDescriptor("ACCESO.R_NOTAS_PARTE_GENERAL",con);
            final ResultSetMetaData metaData = stDesc.getMetaData();
 
            cs = con.prepareCall(llamada);
            // 3- Indicamos que el resultado es de tipo ARRAY
            cs.registerOutParameter(1, OracleTypes.ARRAY, "ACCESO.T_NOTAS_PARTE_GENERAL");
            // Establecemos el Tipo del Parametro de entrada (IN)
            cs.setShort(2, anyo);
            cs.setString(3, conv);
            cs.setString(4, tipo_acceso);
            cs.setString(5, dni);
            cs.setString(6, letra);      
            cs.executeQuery();         
 
 
            Array lista = null;
 
            // 4- Obtenemos el ARRAY JDBC
            if (cs.getArray( 1 ).getClass().getCanonicalName().startsWith( "weblogic.jdbc.wrapper.Array" )) {
                // Con este código obtenemos el objeto OJDBC en lugar del Wrapper de Weblogic
                try {
                    Object weblogicArray = cs.getArray( 1 );
                    Method vendorObjectmethod = Reflections.getMethod( cs.getArray( 1 ).getClass(), "getVendorObj" );
                    lista = (Array) vendorObjectmethod.invoke( weblogicArray );
                }
                catch ( Exception e ) {
                   log.error("Error al obtener el Array de Oracle SQL", e);
                }
            }
            else {
                lista = cs.getArray( 1 );
            }
 
            // 5- Obtenemos el array de Objects Java
            Object[] objectos = (Object[]) lista.getArray();              
            int i = 1;
            // Creamos los datos en la representacion de nuestra aplicacion --> NotaMateria
            for (Object objeto : objectos) {
                // 6- Los objetos del ARRAY JDBC son STRUCT
                STRUCT struct = (STRUCT) objeto;
                NotaMateria nm = new NotaMateria();
 
                // 7- Obtenemos los atributos del STRUCT
                Object[] atributos = struct.getAttributes();
 
                // 8- Iteramos sobre los atributos del STRUCT, para crear el objeto que utilizamos en la aplicacion
                for (Object atributo : atributos) {
                    if (atributo != null) {
                        if("DNI".equals(metaData.getColumnName( i ))) {
                            nm.setDni(atributo.toString());
                        }
                        else if("LETRA".equals(metaData.getColumnName( i ))) {
                            nm.setLetra(atributo.toString());
                        }
                        else if("AÑO".equals(metaData.getColumnName( i ))) {
                            nm.setAño(Short.valueOf( atributo.toString()));
                        }
                        else if("CONV".equals(metaData.getColumnName( i ))) {
                            nm.setConv(atributo.toString());
                        }
                        else if("COD_TIPO_ACCESO".equals(metaData.getColumnName( i ))) {
                            nm.setCodTipoAcceso(atributo.toString());
                        }
                        else if("COD_MATERIA".equals(metaData.getColumnName( i ))) {
                            nm.setCodMateria(atributo.toString());
                        }
                        else if("NUM_CORRECCION".equals(metaData.getColumnName( i ))) {
                            nm.setNumCorreccion(Short.valueOf(atributo.toString()));
                        }
                        else if("NOTA".equals(metaData.getColumnName( i ))) {
                            nm.setNota( Float.valueOf( atributo.toString()));
                            nm.setTextoNota(formatNota(nm.getNota()));
                        }
                        else if("DES_MATERIA".equals(metaData.getColumnName( i ))) {
                            nm.setDesMateria(atributo.toString());
                        }  
                    }
                    i++;                   
                }
                i = 1;
                al.add(nm);  
            }
            this.getLog().info("Salimos del metodo funNotasParteGeneral, resultado [%0]", al.size());          
        } catch(Exception e) {
            log.error("[ACCESO]::[ERROR] :: funNotasParteGeneral :: Error al ejecutar al ejecutar la funcion", e);
        }
        finally {
            close(con, cs, rs);
        }
        // 9- Devolvemos la lista de objetos, con la representacion de la aplicacion
        return al;
    }

JUAN MIGUEL BERNAL GONZALEZ 2016/07/08 12:43