How to call stored procedure that returns a JSON using Spring JPA - spring-boot

I have a stored procedure that returns a JSON instead of usual table. How do I call it using spring JPA? When I called like normal stored procedure it says
SQL Error: 0, SQLState: S1093
Parameter out was not defined for stored procedure
the way I called the stored procedure is
public interface ITransactionserviceJPA extends JpaRepository<CategoryEntity, Integer>{
#Procedure(procedureName = "getApprovalRequests")
String getApprovalRequests(String EmpId);
}
I checked the stored procedure. It did not have any out parameter. But it returns JSON object so I cannot use use void instead of String. But when I use String as return type it gives error. I searched for few hours but I couldn't find any solution. Idk even this is possible or not.

Related

Spring Boot how execute stored procedure multiple times?

I need to execute a procedure multiple times with the requestbody. For now, i am using for loop to do that, but it is not a good way. For example, when the one request is failed, catching that request is a problem. See for the example usage.
Implementation of stored procedure with for-loop;
**Controller**
public void runSP(
#RequestBody List<IdNoteModel> idNotes
){
getService().runSP(idNotes);
}
**Service**
public void runSP(List<IdNoteModel> idNotes){
for (IdNoteModel idNote : idNotes){
getRepository().runSP(idNote);
}
}
**Repository**
#Query(nativeQuery = true, value = "EXECUTE PROCEDURE SP_RUN_ID_NOTE(:id, :note)")
void runSP(Long id, String note);
Is there a better way to run stored procedures multiple times? or do you have an idea to catch the failed requests?
You can use one stored procedure in which you can use the cursor to execute the procedure (SP_RUN_ID_NOTE) multiple times. In that stored procedure, you can also use rollback for something to fail. In your above case, you can store request body input in the table and then call procedure while taking input row from that table.
You can use #Retryable for this purpose and also you can catch exceptions and log requests with #Recover

Assigning NamedStoredProcedureQuery at runtime

I have stored procedures that need to be called to perform the operation. However, for each operation, I have saved the stored procedure name into the database. So, at runtime, based on the operation name I will call the assign stored procedure.
Question:
1. How can I set the name of the NamedStoredProcedureQuery at runtime?
I am using Spring JPA with Spring boot.
#NamedStoredProcedureQueries({
#NamedStoredProcedureQuery(
name = "sptest",
procedureName = "usp_helper_test",
resultClasses = {Config.class},
parameters = {
#StoredProcedureParameter(
name = "data",
type = String.class,
mode = ParameterMode.IN)
})
})
In this above example, I want to set procedureName at runtime.
If we ignore stuff like byte code generation: You can't.
Named stored procedures get their name from the annotations you showed in the question.
Of course you can still use either the EntityManager or JDBC (possibly via the JdbcTemplate) to call stored procedures by the name they have in the database.
With the EntityManager you'd invoke EntityManager.createStoredProcedureQuery in one of it's variants.
For the JdbcTemplate approach you can consult this SO answer.
The code you need to write would go in a custom method implementation.

FUNCTION in WHERE clause of SQL query

I have the following (private) PL/SQL function (inside PACKAGE) returning the previous month in 'YYYYMM' format:
FUNCTION GET_PREV_MONTH RETURN VARCHAR2 IS
BEGIN
RETURN TO_CHAR(ADD_MONTHS(SYSDATE,-1),'YYYYMM');
END GET_PREV_MONTH;
I need to compare if records are from previous month in several my queries so I wanted to make private function returning previous month. Why I cannot use this return value from GET_PREV_MONTH() function in WHERE clause of my other SQL queries like:
UPDATE mytable t SET t.col=1
WHERE TO_CHAR(t.created,'YYYYMM')=GET_PREV_MONTH();
Oracle says PLS_00231: function 'GET_PREV_MONTH' may not be used in SQL.
If I create this, this works!
UPDATE mytable t SET t.col=1
WHERE TO_CHAR(t.created,'YYYYMM')=TO_CHAR(ADD_MONTHS(SYSDATE,-1),'YYYYMM');
I wanted to make private function returning previous month. Why I cannot use this return value from GET_PREV_MONTH() function in WHERE clause of my other SQL queries
It is a private function - you cannot reference it outside the package.
If you want to use it in SQL then declare it in the package specification so that it is public.
This is private function of this package! This function is used in procedures from the same package. It is not referenced outside this package.
It CANNOT be used in the SQL context if it is not a public function; regardless of whether the SQL is being called from inside or outside the same package.

Mybatis Oracle Stored Procedure

I am having problem calling oracle Stored Procedure and getting Output parameters from Oracle Stored Procedure.
Here is my mapper
AppUserMapper.java
public interface AppUserMapper {
#Select(value= "{ CALL sp_check_user( #{userId, mode=IN, jdbcType=VARCHAR }, #{userPwd, mode=IN, jdbcType=VARCHAR}, #{userType, jdbcType=VARCHAR, mode=OUT} )}")
#Options(statementType = StatementType.CALLABLE)
Object getUserType(String userId,String UserPwd);
}
Dao call
Map<String, Object> retrurnStatus = (Map<String, Object>) appUserMapper.getUserType(userId,UserPwd);
Here is Stored Procedure code
CREATE OR REPLACE PROCEDURE HR.sp_check_user (userId VARCHAR,userPwd VARCHAR, userType OUT VARCHAR )
AS
BEGIN
BEGIN
select user_type into userType from appuser where USER_ID = userId and USER_PWD = userPwd ;
EXCEPTION
WHEN NO_DATA_FOUND THEN
userType := 'Invalid';
END ;
END ;
/
It is executing stored procedure but giving error
DEBUG 2014-04-12 09:51:56,948 org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl: ==> Preparing: { CALL sp_check_user( ?, ?, ? ) }
DEBUG 2014-04-12 09:51:57,103 org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl: ==> Parameters: abc(String), abc1(String)
Could not complete request
java.lang.NullPointerException
at com.appuser.dao.AppUserDaoImpl.getUserType(AppUserDaoImpl.java:33)
I had been trying multiple options but could not find sample which I can take as is and try.
I will relay appropriate help on this as I have been trying to use oracle stored procs in mybatis with multiple input and output parameters.
Can someone provide simple example for calling Oracle stored procedure using mybatis for multiple input output parameters?
Jeff Butler says in mybatis-user group:
For stored procedure parameters, MyBatis will map both input and
output parameters to properties in the parameterType.
You can try sending a Map, POJO or three annotated variables having userId, userPwd and userType. After the SP is called, MyBatis will set the OUT parameter to userType.
I cannot try it now, I'll try to edit the answer later. But can you try these,
1) Define your function as follows, and check if userType is updated after you call the SP.
void getUserType(Param("userId") String userId, Param("userPwd") String userPwd, Param("userType") String userType);
or
2) Create a Map, add 3 key-value pairs, i.e. ("userId", 1234), ("userPwd", 666), ("userType, null) tuples. After you call the SP, you can try getting the userType value.
void getUserType(Map<String, Object> myMap);
or
3) Create a class with 3 variables (userId, userPwd, userType), getters, setters. Set userId and userPwd values. Call the SP. Then, userObj.getUserType().
void getUserType(UserClass userObj);

How Can I get return values returned by stored procedure using InsertOnSubmit in LINQ

Can I get return values returned by stored procedure using InsertOnSubmit in LINQ.
The stored procedure return a error number. How can I get this error number InsertOnSubmit (using stored procedure instead of Runtime sql). Many Thanks
On the data-context are a number of partial methods for insert/update/delete of each entity type; if you implement the other half of this, you can provide your own SP logic:
partial class MyDataContext {
partial coid UpdateMyEntity(MyEntity instance) {
// your ADO.NET code and/or ExecuteCommand here...
}
}
Note that if you use a separate connection you won't have the same transaction etc (unless it uses TransactionScope).
I overloaded the default function generated by LINQ designer and followed the below steps.
Created a public readonly property _ReturnCode
In the overloaded function I used _ReturnCode = CType(result.ReturnValue, Integer)
Public Function FUNC_NAME( ByRef .....
Dim result As IExecuteResult = Me.ExecuteMethodCall(Me, CType(MethodInfo.GetCurrentMethod, MethodInfo), ......)
ID= CType(result.GetParameterValue(0), System.Nullable(Of System.Guid))
_ReturnCode = CType(result.ReturnValue, Integer)
Return CType(result.ReturnValue, Integer)
End Function
Let me know if anybody has a better answer. Many Thanks

Resources