Search code examples
javaoracle-databasehibernatejpasys-refcursor

How to call Oracle Function or Procedure using Hibernate (EntityManager) or JPA


I have an Oracle function which return sys-refcursor and when I call this function using Hibernate, I am getting the following exception.

Hibernate: { ? = call my_function(?) }
 org.hibernate.exception.GenericJDBCException: could not execute query
javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: could not execute query
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1360)
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1288)
    at org.hibernate.ejb.QueryImpl.getSingleResult(QueryImpl.java:313)

How can I resolve this?

Oracle function

create or replace 
FUNCTION my_function(p_val IN varchar2)
    RETURN SYS_REFCURSOR
  AS
    my_cursor SYS_REFCURSOR;
  BEGIN
    OPEN my_cursor FOR SELECT emp_name FROM employees
    WHERE lower(emp_name) like lower(p_val||'%');
    RETURN my_cursor;    
  END;

My Entity class

@Entity
@javax.persistence.NamedNativeQuery(name = "getFunc", query = 
"{ ? = call my_function(:empName) }", 
 resultClass = Employee.class, hints = 
 { @javax.persistence.QueryHint(name = "org.hibernate.callable", value = "true") })
 @Table(name = "EMPLOYEES")

and in DAO

    @Override
        public void findEmployees(QueryData data,
                String empName) {

        List query = (List) entityManager.createNamedQuery("getFunc")
                         .setParameter("empName", empName)
                         .getSingleResult();
                data.setResult(query);
}

Solution

  • Oracle function or a stored procedure can be called using EntityManager in the following manner.

    For Oracle Function

    Create a function with sys_refcursor as return type

    CREATE OR REPLACE FUNCTION my_function
    (p_val IN varchar2)
        RETURN SYS_REFCURSOR
      AS
        my_cursor SYS_REFCURSOR;
      BEGIN
        OPEN my_cursor FOR SELECT emp_name FROM employees
        WHERE lower(emp_name) like lower(p_val||'%');
        RETURN my_cursor;    
      END;
    

    In Entity class, define function as

    @javax.persistence.NamedNativeQuery(name = "getFunc", query = "{? =  call
    my_function(:empName) }", resultClass = Employee.class, hints = {
    @javax.persistence.QueryHint(name = "org.hibernate.callable", value = "true") })
    

    For Oracle Stored Procedure

    Create procedure with sys_refcursor as first OUT parameter

    CREATE OR REPLACE PROCEDURE myProcedure(p_cursor out sys_refcursor,
         p_val  in varchar2
    )
     AS
    BEGIN
         OPEN o_cursor FOR
              SELECT     emp_name 
                 FROM     employees 
                WHERE     LOWER (emp_name) LIKE lower(p_val||'%');
    

    In Entity class define procedure as

    @javax.persistence.NamedNativeQuery(name = "getProc", query = "{ call
    my_procedure(?,:empName) }", resultClass = Employee.class, hints = {
    @javax.persistence.QueryHint(name = "org.hibernate.callable", value = "true") })
    

    and finally in DAO class, call function or procedure as

    Query query = entityManager.createNamedQuery("getFunc"); // if procedure then getProc 
    query.setParameter("empName","smith"); 
    query.getResultList(); 
    

    Thanks