Beleza, Marco!
Vou descrever aqui até mesmo porque alguém pode dar outra solução.
Meu ambiente é Spring Boot + Weblogic + Oracle.
Meu problema inicial é que tenho esta procedure:
PROCEDURE getRolesTeste( username IN VARCHAR,
appCode IN VARCHAR,
centrosaude IN NUMBER,
idPerfil IN NUMBER,
resultado OUT SYS_REFCURSOR);
A procedure funciona, consigo fazer o Call utilizando o outras ferramentas e por linha de comando.
Quero fazer o Call utilizando o JPA (ou o Spring data).
Com procedures sem o Cursor resultado OUT SYS_REFCURSOR, funciona normalmente. Porém quando tenho o cursor, tentei de várias formas, não consegui fazer o Call da Procedure.
Utilizando Statement e diretamente JDBC com uso de classes como Oracle Types funciona.
Mas quando tento diretamente com JPA, acontece o erro abaixo. parece que o erro é na forma de registrar o Cursor.
Caused by: org.hibernate.exception.GenericJDBCException: Error registering REF_CURSOR parameter [resultado]
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:47)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:111)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:97)
at org.hibernate.engine.jdbc.cursor.internal.StandardRefCursorSupport.registerRefCursorParameter(StandardRefCursorSupport.java:72)
at org.hibernate.procedure.internal.AbstractParameterRegistrationImpl.prepare(AbstractParameterRegistrationImpl.java:353)
at org.hibernate.procedure.internal.ProcedureCallImpl.buildOutputs(ProcedureCallImpl.java:444)
at org.hibernate.procedure.internal.ProcedureCallImpl.getOutputs(ProcedureCallImpl.java:404)
at org.hibernate.procedure.internal.ProcedureCallImpl.outputs(ProcedureCallImpl.java:663)
at org.hibernate.procedure.internal.ProcedureCallImpl.getResultList(ProcedureCallImpl.java:751)
... 76 common frames omitted
Caused by: java.sql.SQLException: Invalid column type: 2012
at oracle.jdbc.driver.OracleStatement.getInternalType(OracleStatement.java:3978)
at oracle.jdbc.driver.OracleCallableStatement.registerOutParameterInternal(OracleCallableStatement.java:140)
at oracle.jdbc.driver.OracleCallableStatement.registerOutParameterInternal(OracleCallableStatement.java:2401)
at oracle.jdbc.driver.OracleCallableStatement.registerOutParameter(OracleCallableStatement.java:2307)
at oracle.jdbc.driver.OracleCallableStatementWrapper.registerOutParameter(OracleCallableStatementWrapper.java:1250)
at weblogic.jdbc.wrapper.CallableStatement_oracle_jdbc_driver_OracleCallableStatementWrapper.registerOutParameter(Unknown Source)
at org.hibernate.engine.jdbc.cursor.internal.StandardRefCursorSupport.registerRefCursorParameter(StandardRefCursorSupport.java:69)
... 81 common frames omitted
A questão é o mapeamento do Cursor Oracle, inclusive o mesmo código com DB2 funciona sem problemas.
Para conseguir fazer funcionar segui o seguinte caminho:
Tranformei a Procedure em Function
FUNCTION getRoles( username IN VARCHAR,
appCode IN VARCHAR,
centrosaude IN NUMBER default null,
idPerfil IN NUMBER)RETURN SYS_REFCURSO
Utilizei named native query, para mapear a função e para executar TypedQuery.
@NamedNativeQuery(
name = "getRoles",
callable = true,
query = "{? = call NEW_WEBRNU_TESTE.GETROLES(?,?,?,?)}",
resultClass = Role.class )
TypedQuery<Role> query = entityManager.createNamedQuery("getRoles", Role.class);
query.setParameter(0, userName);
query.setParameter(1, appCode);
query.setParameter(2,centroSaude !=null ?centroSaude:Types.NULL);
query.setParameter(3, perfil!=null?perfil:Types.NULL);
List<Role> roles = query.getResultList();
Este último código funciona.
Obs: neste codigo
- query.setParameter(2,centroSaude !=null ?centroSaude:Types.NULL);
o Types.NULL na verdade é o valor ZERO e o banco recebe o zero como parâmetro, mas na verdade quero que o banco receba null. Mas esta será questão para outro tópico.