如何通过Java EntityManager调用PL / SQL存储函数

时间:2014-11-25 15:35:20

标签: java sql plsql entitymanager

我有这个功能

create or replace
FUNCTION IFRS_FUNCTION_TEST RETURN NUMBER IS

estado NUMBER;
excepciones NUMBER;
title_code VARCHAR2(150 char);
colgaap_code VARCHAR2(150 char);
ifrs_code VARCHAR2(150 char);
v_causacion VARCHAR2(150 char);
pyg_diario_value VARCHAR2(150 char);
fecha_valoracion VARCHAR2(150 char);
pyg_dialogo VARCHAR2(150 char);

CURSOR ifrscursor IS SELECT no_asignado_por_la_entidad, codigo_puc FROM IFRS_351 WHERE no_asignado_por_la_entidad LIKE 'W%' FOR UPDATE;

BEGIN
        BEGIN
        estado:=0;
        excepciones:=0;
        OPEN ifrscursor;
        LOOP
            FETCH ifrscursor INTO title_code, colgaap_code; 
            EXIT WHEN ifrscursor%NOTFOUND;
            SELECT cta_ifrs into ifrs_code FROM ifrs_tabla_homo_351 WHERE codigo_puc_colgaap = colgaap_code;
            UPDATE IFRS_351 SET codigo_puc = ifrs_code WHERE CURRENT OF ifrscursor;
            BEGIN
                SELECT saldo, pyg_diario into v_causacion, pyg_diario_value FROM IFRS_INV_OBL WHERE nro_titulo=title_code;
                UPDATE IFRS_351 SET vr_mercado_o_valor_presente_ = v_causacion, causacion_valoracion_cuentas = pyg_diario_value WHERE CURRENT OF ifrscursor;
            EXCEPTION WHEN NO_DATA_FOUND THEN
                excepciones:=excepciones+1;
            END;
END LOOP; 
CLOSE ifrscursor;
EXCEPTION WHEN OTHERS THEN
    estado:=SQLCODE;  
END;
RETURN(estado);

我怎样才能获得' estado' Java EntityManager使用此函数的值?我试试

SELECT IFRS_FUNCTION_TEST() FROM DUAL;

但我得到的值是-14551;

4 个答案:

答案 0 :(得分:1)

值-14551实际上是Oracle错误而不是值。错误详述如下,并应详细说明其无法正常工作的原因。

  

ORA-14551无法在查询中执行DML操作原因:DML   像insert,update,delete或select-for-update这样的操作不能   在查询内或在PDML从属下执行。行动:确保   违规DML操作不会执行或使用自治   事务在查询或PDML中执行DML操作   从设备。

答案 1 :(得分:1)

您不能使用SELECT查询来检索包含DML语句的函数的值。您必须使用显式调用。 喜欢的东西(未经测试):

Object result = em.createNativeQuery("{ ? = CALL IFRS_FUNCTION_TEST() }")
                    .getSingleResult();

编辑:因为这似乎工作,另一个选择是直接通过JDBC(通过session.getConnection())发送该查询。 喜欢的东西可能是:

CallableStatement statement = session.connection().prepareCall(
        "{ ? = CALL IFRS_FUNCTION_TEST() }");
statement.registerOutParameter(1, Types.OTHER);
//                                      ^^^^^
//                       use the right type here of course
statement.execute();
Object result = statement.getObject(1);

有关详细信息,请参阅OracleCallableStatement的文档。

答案 2 :(得分:0)

JPA 2.0不支持RETURN值,只支持调用。 JPA 2.1解决了这个问题,

如果您使用的是JPA 2.0。 我的解决方案是。创建一个调用PROCEDURE的FUNCTION。 因此,在JAVA代码中,您执行一个调用oracle FUNCTION的NATIVE QUERY。

或者 使用createStoredProcedureQuery

答案 3 :(得分:0)

以下是使用javax.persistence.EntityManager的解决方案:

@PersistenceContext
private EntityManager entityManager;

. . .

int estado;
Session session = entityManager.unwrap(Session.class);
session.doWork(connection -> {
    try (CallableStatement function = connection.prepareCall(
            "{ ? = call IFRS_FUNCTION_TEST() }" )) {
        function.registerOutParameter( 1, Types.INTEGER );
        function.execute();
        estado = function.getInt(1);
    }
} );

这些是主要的依赖关系,用于指示该解决方案使用的lib版本:

compile 'com.oracle:ojdbc6:11.2.0.4.0'
compile 'org.hibernate:hibernate-core:5.4.7.Final'
compile 'org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.2.Final'

作为doWork()的替代方法,并用getXxx(1)分配存储的函数结果,可以使用doReturningWork()

正如其他人指出的那样,由于函数内的UPDATE(DML)命令,您不能使用(本机)查询。

在科特林

这是Kotlin中的解决方案(并使用doReturningWork):

@PersistenceContext
lateinit var entityManager: EntityManager

. . .

val session : Session = entityManager.unwrap(Session::class.java)
var estado = session.doReturningWork { connection: Connection ->
    connection.prepareCall(
            "{ ? = call IFRS_FUNCTION_TEST() }").use { function ->
        function.registerOutParameter(1, Types.INTEGER)
        function.execute()
        return@doReturningWork function.getInt(1)
    }
}