====== Obtener una Colección mediante JDBC ====== Para mapear objetos colección mediante JDBC, vamos a mostrar el ejemplo utilizado para [[plsql:pl_sql#procedure_que_devuelve_ref_cursor_no_cierra_cursor|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. * En la declaración de la función, primero creamos el objeto //t_notas// del tipo //ACCESO.T_NOTAS_PARTE_GENERAL// y obtenemos el cursor //c_notas_general//. * En el cuerpo, tenemos un bucle, donde en cada iteración, creamos un objeto //ACCESO.R_NOTAS_PARTE_GENERAL// y lo asigna a la posición indicada por el indice //i// de //t_notas//. En cada iteración, se llama a //t_notas.Extend// para extender en una fila a //t_notas//, antes de la asignación del nuevo objeto //ACCESO.R_NOTAS_PARTE_GENERAL// creado. 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 funNotasParteGeneral(short anyo, String conv, String tipo_acceso, String dni, String letra) { Connection con = null; CallableStatement cs = null; ResultSet rs = null; List al = new ArrayList(); try { Map logParams = new LinkedHashMap(); 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; } --- //[[juanmiguelbg@um.es|JUAN MIGUEL BERNAL GONZALEZ]] 2016/07/08 12:43//