Execute database function with JPA
Solution 1
- Select Query will not work when there are any DML statements in the function.
If there are no DML statements then SELECT QUERY is the best and efficient way to proceed. - If there are DML statements, then you have to go with interface CallableStatement.
It is pretty forward when we are using JDBC in our project, but for Spring Project i.e. using JPA we will need to obtain the session from EntityManager and ReturningWork.
Session session = entityManager.unwrap(Session.class);
CallableStatement callableStatement = session.doReturningWork(new ReturningWork<CallableStatement>() {
@Override
public CallableStatement execute(Connection connection) throws SQLException {
CallableStatement function = connection.prepareCall(
"{ ? = call package_name.function_name(?,?) }");
function.registerOutParameter(1, Types.INTEGER);
function.setLong(2, 56);
function.setString(3,"some text");
function.execute();
return function;
}
});
try {
return callableStatement.getBigDecimal(1);
} catch (SQLException e) {
e.printStackTrace();
return null;
}
Solution 2
You must use a StoredProcedureQuery:
StoredProcedureQuery query = this.em.createStoredProcedureQuery("myfunction");
query.registerStoredProcedureParameter("inparam", String.class, ParameterMode.IN);
query.registerStoredProcedureParameter("outparam", String.class, ParameterMode.OUT);
// set input parameter
query.setParameter("inparam", "Hello);
// call the stored procedure and get the result
query.execute();
String result = (String) query.getOutputParameterValue("sum");
If you are expecting one or more results you can use
getSingleResult() or getResultList()
like on the Query interface instead of getOutputParameterValue()
Find more information here: https://www.thoughts-on-java.org/call-stored-procedures-jpa-part-2/
anste
Working in Aachen, living nearby. Playing with various tools to improve GIS Software.
Updated on September 04, 2022Comments
-
anste over 1 year
To call an Oracle database function I'd simply write
final Query query = entityManager.createNativeQuery( "select myfunction(?) from dual" ); query.setParameter(1, "value"); Object rv = query.getSingleResult();
This works as long as the called function doesn't execute any dml operations. Otherwise I'd have to execute something like
{? = call myfunction(?)}
Unfortunately I can't register any OUT parameters, so I can't get this statement to work. How can I achieve that without using plain JDBC?
Edit:
The question was misleading. I want to fetch the result of a function (not a stored procedure) in an Oracle database. There are no OUT parameters. The function could look like this:
CREATE OR REPLACE FUNCTION myfunction(value IN VARCHAR2) RETURN VARCHAR2 IS BEGIN UPDATE foo SET bar = 'foobar' WHERE id = 1; RETURN 'test'; END myfunction;
The answer to Calling an oracle function from JPA does not solve my problem since there are dml changes inside my function. I get an error:
cannot perform a DML operation inside a query
-
anste over 6 yearsI edited my question. I want to fetch the return value of a function, not any OUT parameter.
-
Simon Martinelli over 6 yearsThere is getResultList() and getSingleResult on the Query interface have a look at the docs docs.oracle.com/javaee/7/api/javax/persistence/…
-
anste over 6 yearsThank you for your help, but I can't get this to work. Hibernate always creates a statement like "{call myfunction(?)}". So a procedure is expected and I get "myfunction is not a procedure or is undefined". Could you give an example?
-
coladict over 6 yearsI believe the query is transformed into
"{call myfunction(?)}"
when usingcreateStoredProcedureCall
orcreateStoredProcedureQuery
. If you need just the return, then just usecreateNativeQuery
. -
anste over 6 years@coladict how would a solution with createNativeQuery look like without using select?
-
coladict over 6 yearsWell, normally you'd just do
select myfunction(?)
, but I just checked and Oracle doesn't allow for select withoutfrom
. Maybe you could doselect * from myfunction(?)
. -
anste over 6 yearsSELECT can't be used if the function contains DML operations. Otherwise I would write 'select myfunction(?) from dual'.