spring-data-jpa not casting from oracle.jdbc.driver.forwardonlyreswultset - java

i'm making a connection to an oracle db. I just solved problem with dependency (into the following url there's the needed code like respository, entity etc.):
spring-data-jpa 1.11.16 stored procedure with cursor
Now i'm facing problem with casting exeption when i call the repository.
The repository sent me back a list of ForwardOnlyResultSet and i'm not able to map my results.
that's the error:
Cannot cast 'oracle.jdbc.driver.ForwardOnlyResultSet' to 'procedure.entity.PocRegions'
my oracle pl/sql procedure is that:
PROCEDURE PRO_RETURN_REGION(
id_region IN POC_REGIONS.REGION_ID%TYPE,
o_cursor OUT SYS_REFCURSOR) is
BEGIN
--Opening the cursor to return matched rows
open o_cursor for
select *
from POC_REGIONS
where POC_REGIONS.REGION_ID = id_region;
END PRO_RETURN_REGION;
Then i tryed to bot implement the call with jpa calls and spring-data-jpa call:
StoredProcedureQuery query = entityManager.createStoredProcedureQuery( "POC_PKG_GEO.PRO_RETURN_REGION");
query.registerStoredProcedureParameter("id_region", BigDecimal.class, ParameterMode.IN);
query.registerStoredProcedureParameter("o_cursor", void.class, ParameterMode.REF_CURSOR);
query.setParameter("id_region", id);
query.execute();
//Contains a forwardonlyreswultset (jpa call)
Object res = query.getOutputParameterValue("o_cursor");
//Contains an array of 2 Object not mapped (jpa call)
List<PocRegions> resultList = query.getResultList();
//Contains a forwardonlyreswultset (spring-data-jpa call)
List<PocRegions> region = geoRegionRepo.getRegion(id);
How should I be supposed to convert/map the retrieved value, to my entity?
Thank you

Related

How to retrieve output param from Stored Procedure with Hibernate

I am trying to execute a Stored Procedure which updates a column and retrieves the filename from the same table after updating
StoredProcedure:
CREATE DEFINER=`test`#`%` PROCEDURE `update_count`(
IN in_testID VARCHAR(64),
OUT out_FileName VARCHAR(100),
OUT out_Message VARCHAR(100))
BEGIN
UPDATE files SET count=count+1 WHERE testID=in_testID;
SELECT FileName INTO out_FileName FROM files WHERE testID = in_testID;
SET out_Message = 'File updated uccessfully';
END
JavaCode to execute this StoredProcedure:
Query query = session.createSQLQuery("CALL update_count(:in_testID, #out_FileName, #out_Message)").addEntity(FilesBean.class)
.setParameter("in_testID",body.getTestId());
query.executeUpdate();
Updated the query.executeUpdate() with query.list(). But the line returning a error ResultSet is from UPDATE. No Data
I need to fix this with using the createSQLQuery
The easiest way to do that is return the out parameter as part of the returning parameters (relevant only if you have access to the store procedures).
just add a store procedure like the following one
create procedure myProcedure_only_in_prams (
in in_Id int)
begin
call myProcedure(in_id,#out_Id) ;
select #out_id
END;
after done that it quite simple to use it with Hibernate in the following way
Query query = session.createSQLQuery(
"CALL myProcedure_only_in_parms (:in_Id)")
.setParameter("in_id", 123);
List result = query.list();
The result contains the out parameter, if you want return multiply parameters you can add it by doing select #parm1,#parm2,... ,#parmn
Hope it helped

How can I correctly implement an Hibernate SQL query starting from an SQL query that count the number of rows?

I am absolutly new in Hibernate and I have the following problem.
I have this standard SQL query:
SELECT count(*)
FROM TID003_ANAGEDIFICIO anagraficaEdificio
INNER JOIN TID002_CANDIDATURA candidatura
ON (candidatura.PRG_PAR = anagraficaEdificio.PRG_PAR AND candidatura.PRG_CAN = anagraficaEdificio.PRG_CAN)
INNER JOIN TID001_ANAGPARTECIPA anagPartecipa ON(anagPartecipa.PRG_PAR = candidatura.PRG_PAR)
INNER JOIN anagrafiche.TPG1029_PROVNUOIST provNuovIst ON (provNuovIst.COD_PRV_NIS = anagPartecipa.COD_PRV_NIS)
WHERE anagraficaEdificio.FLG_GRA = 1 AND provNuovIst.COD_REG = "SI";
This works fine and return an integer number.
The important thing to know is that in this query the only
parameter that can change (inserted by the user in the frontend of a webappplication) is the last one (this one: provNuovIst.COD_REG = "SI").
So, the application on which I am working use Hibernate and the requirement say that I have to implement this query using Hibernate Native SQL, I have found this tutorial:
http://www.tutorialspoint.com/hibernate/hibernate_native_sql.htm
that show this example:
String sql = "SELECT * FROM EMPLOYEE WHERE id = :employee_id";
SQLQuery query = session.createSQLQuery(sql);
query.addEntity(Employee.class);
query.setParameter("employee_id", 10);
List results = query.list();
that, from what I have understand (correct me if I am doing wrong assertion), involves the use of an Employee model class. So th prvious query first define the query (using the :param_name syntax for the parameter), then create an SQLQuery Hibernate object, add the class used for the result, set the previous parameter neam and finally obtain a List (that I think Hibernate create as something like an ArrayList) with the retrieved object.
My problem is that I simply I have to obtain an integer value (because I have a SELECT count(*), so I will obtain an integer value and not a set of rows).
So how can I correctly use the Hibernate Native SQL to implement my SQL query into my Hibernate repository class?
Use SQLQuery.uniqueResult to retrieve a single value from the query:
String sql = "SELECT count(*) ...";
SQLQuery query = session.createSQLQuery(sql);
// set parameters...
int count = ((Number)query.uniqueResult()).intValue();

JPA 2.1 StoredProcedureQuery with PostgreSQL and REF_CURSORs

I have a function I created in my PostgreSQL DB that I want to call using JPA 2.1's StoredProcedureQuery method.
Here is my PostgreSQL query:
CREATE OR REPLACE FUNCTION get_values(date text) returns refcursor
AS $$
DECLARE tuples refcursor;
BEGIN OPEN tuples FOR
SELECT user, COUNT(*)
FROM my_table
WHERE date_ = date
GROUP BY user;
return tuples;
END;
$$
LANGUAGE plpgsql
This is just a simple query to count users on a particular day. This is just a demo query to test how the StoredProcedureQueries work. And in fact, it works just fine when used via postgreSQL alone.
Now, let's try and call this using JPA 2.1 and in Javaland:
StoredProcedureQuery storedProcedure = em.createStoredProcedureQuery("get_values");
storedProcedure.registerStoredProcedureParameter(2, String.class, ParameterMode.IN);
storedProcedure.registerStoredProcedureParameter(1, Object.class, ParameterMode.REF_CURSOR);
storedProcedure.setParameter(2, "2015-02-01");
storedProcedure.execute();
When I do this, I get back the following exception:
org.hibernate.HibernateException: PostgreSQL supports only one REF_CURSOR parameter, but multiple were registered
There is only a single ref cursor declared! In fact, if I just register the single REF_CURSOR parameter and hardcode in a value for my Postgresql function for the WHERE date_ = date, this call works just fine.
So it would seem adding any additional parameters to a storedprocedurequery with a ref_cursor breaks the functionality. Alone, the ref_cursor parameters works fine.
Anybody see why this would happen?? Why is it that adding parameters to the StoredProcedureQuery for my PostgreSQL function breaks it?
Example of when it works:
CREATE OR REPLACE FUNCTION get_values(date text) returns refcursor
AS $$
DECLARE tuples refcursor;
BEGIN OPEN tuples FOR
SELECT user, COUNT(*)
FROM my_table
WHERE date_ = '2015-02-01'
GROUP BY user;
return tuples;
END;
$$
LANGUAGE plpgsql
and in javaland:
StoredProcedureQuery storedProcedure = em.createStoredProcedureQuery("get_values");
storedProcedure.registerStoredProcedureParameter(1, Object.class, ParameterMode.REF_CURSOR);
storedProcedure.execute();
Short answer: Reverse the order of your two calls to registerStoredProcedureParameter():
storedProcedure.registerStoredProcedureParameter(1, Object.class, ParameterMode.REF_CURSOR);
storedProcedure.registerStoredProcedureParameter(2, String.class, ParameterMode.IN);
Long answer: I did some digging in the Hibernate source code for Postgress callable statement support, and found that each registerStoredProcedureParameter() call creates a ParameterRegistrationImplementor instance that gets tacked into a list and passed around. You'll note that this class stores the position of the parameter, which is independent of its position within the list.
Later, this list is analyzed and assumes that the REF_CURSOR parameter will be first in line, and throws your error message if a REF_CURSOR parameter is not first, regardless of what the parameter number is.
Not a very bright way of doing things (IMHO), but at least the workaround is easy: if you swap the order of your calls, you should be fine.

How to execute a JPA Bulk Update statement which takes a List as a parameter value

I have an Update Query that looks like this
UPDATE
table_name
SET
column_name = ?
WHERE
column_name = ? AND id in (?)
So the JPA transaction is
em.createNativeQuery(Update_QUERY)
.setParameter(1, updatedStatus)
.setParameter(2, currentStatus)
.setParameter(3, ids)
.executeUpdate();
The Input to the method is List id, currentStatus, and updatedStatus
How do I pass the List as a single parameter, if I convert the List to a comma-separated String I get the error Specified text is not number as strings is not allowed in the In clause.
How do I pass the List as a single parameter
An example approach:
String jpql = "UPDATE NameEntity ne " +
"SET ne.valstring = :updated_status " +
"WHERE ne.valstring = :current_status AND ne.id IN :ids";
em.createQuery(jqpl)
.setParameter("updated_status", updatedStatus)
.setParameter("current_status", currentstatus)
.setParameter("ids", Arrays.asList(ids))
.executeUpdate();
Three simple rules:
Use native SQL for bulk update / delete on tables that are not mapped to entities.
Native SQL queries work directly on database tables bypassing the persistence context (a set of managed entities), so it is safe to use such queries if a given database table has no corresponding entity.
Use JPQL for bulk update / delete on tables that are mapped to entities
In case of a given database table is mapped by an entity, using a SQL update / delete will lead to inconsistency between persistence context and the underlying database, so use JQPL counterparts instead and the persistence provider will take care of consistency.
Bulk update / delete should be executed as the first operation within the transaction or ideally in its own transaction.
Setting a List parameter
The JPA Query interface setParameter method that accepts an Object parameter:
Query setParameter(String name, Object value)
can take a List as the parameter value.
This works in the same way for JPQL, Criteria API, or bulk update and delete queries:
List<Post> posts = entityManager.createNativeQuery("""
UPDATE
post
SET
status = :newStatus
WHERE
status = :oldStatus AND
id IN :ids
""", Post.class)
.setParameter("oldStatus", PostStatus.PENDING)
.setParameter("newStatus", PostStatus.APPROVED)
.setParameter("ids", List.of(1L, 2L, 3L))
.executeUpdate();
For more details about executing bulk update and delete statements with JPA and Hibernate, check out this article as well.

how to execute the stored procedure in hibernate 3

I am new in hibernate. I am using hibernate 3 in my application using hibernate annotations , I am developing application in struts 1.3.
My question is :
I have googled a lot but could not understand how to call a stored procedure in hibernate using annotations , I have a simple scenario : suppose I have 2 fields in my jsp say 1) code 2) name , I have created a stored procedure in database for inserting those records into table. Now my problem is that how to execute it
List<MyBean> list = sessionFactory.getCurrentSession()
.getNamedQuery("mySp")
.setParameter("code", code)
.setParameter("name", name)
I don't know the exact code how to do this. But I guess something like that actually I come from jdbc background therefore have no idea how to do this and same thing I want when selecting the data from database using stored procedure.
Hibernate provides many simple ways to call a SP like
Native SQL
Named Query in native SQL as Annotation/XML mapping file
Following link shows how each of above can be implemented
http://www.mkyong.com/hibernate/how-to-call-store-procedure-in-hibernate/
http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/querysql.html#sp_query
Sample to run native SQL query using hibernate:
Session session = getSession();
SQLQuery sqlQuery = session.createSQLQuery("SELECT COUNT(id) FROM tableName WHERE external_id = :external_id");
sqlQuery.setParameter("external_id", idValue);
int count = ((BigInteger) sqlQuery.uniqueResult()).intValue();
releaseSession(session);
You can execute your stored procedure using Hibernate's SQLQuery with the same SQL as when you call it against the database. For example, in postgreSQL:
String query = "select schema.procedure_name(:param1)";
SQLQuery sqlquery = sessionFactory.getCurrentSession().createSQLQuery(query);
sqlquery.setInteger("param1", "this is first parameter");
sqlQuery.list();
Hope it helps.

Categories

Resources