Calling StoredProcedure using JPA in Spring Boot - jpa

I am trying to call a stored procedure, which is built in mysql, in my Spring boot app using JPA. My stored procedure returns the result which cant be contain in single model as it fetches data from combination of tables.
I can do this with "call " but i guess that is not JPA's way. COuld you please let me know what is the best way to do it?

In case you're using plain JPA you need to do a native query call. Something like below.
Query q = em.createNativeQuery("select my_store_pro(?, ?)");
List<Object[]> results = q.getResultList();
for (Object[] a : results) {
System.out.println("result " + a[0] + " " + a[1]);
}
If you're using Spring Data repositories then you want something like below.
#Query(nativeQuery = true, value = "select my_store_pro(?, ?)")
Date callMyStoreProc(int val1, int val2);

Related

Spring Data JDBC and specification pattern

We got an Spring Boot 2 application using Spring Data JDBC. Its displaying a list of orders which needs to be filtered for many different aspects and combinations. Therefore, our Repository is growing more and more, because for new combinations find* methods are added or new parameters are applied.
public interface OrderJdbcRepository extends PagingAndSortingRepository<OrderEntity, Long> {
String ORDER_FILTER = "WHERE ..."; // big custom sql statement
String NOT_BILLED = "...";
Optional<OrderEntity> findById(String orderId);
#Query(
"SELECT o.* FROM `ORDER` AS o "
+ ORDER_FILTER
+ "ORDER BY o.ORDER_ID "
+ "LIMIT :limit OFFSET :offset"
)
List<OrderEntity> findFiltered(String customerId, LocalDate startDate,
LocalDate endDate, ...some other filter criterias, int limit, long offset);
#Query(
"SELECT o.* FROM `ORDER` AS o "
+ ORDER_FILTER + NOT_BILLED // additional filter for not billed orders
+ "ORDER BY o.ORDER_ID "
+ "LIMIT :limit OFFSET :offset"
)
List<OrderEntity> findFilteredAndNotBilled(String customerId, LocalDate startDate,
LocalDate endDate, ...some other filter criterias, int limit, long offset);
// many other methods which looks similar
I'm afraid of that this leads to unmaintainable code. Therefore I'm trying to use the composite specification pattern like its described in the link. For example i just need to combine CustomerIdSpecification, DateBetweenSpecification and NotBilledSpecification. However, the linked tutorial is for Spring Data JPA with Criteria API, which does not exist in Spring Data JDBC. So I'm thinking of how i could solve this problem in Spring Data JDBC.
I need a way to define the custom sql in each specification and pass it to my OrderJdbcRepository. An alternative I thought is to use JdbcTemplate for building a custom sql and accessing my data by hand. Are there other solutions, which I did not think of?
Thanks so far!

Native query not working when specifying column name

I am trying to fetch data using native query method. I am able to fetch data using spring data JPA repository declared methods (findAll() etc) and using JPQL Queries.
When I am using Native query method , "select * from" is working. But when I am specifying "select username from " method is not working. Means When specifying column name, it is not working.
I am adding my code like this,
#Query(value = "select u.username from users u" , nativeQuery = true)
List<Users> findByUsername();
But the query using select * from users is working with no problem. Is this native query nature? Or is there any limited type of format the provider defines?
I think the problem is with your return variable.
When you run "*select * from...*" query, you can return list of Users.
However, you want to fetch a column which is probably a varchar, so that you should return List of String:
#Query(value = "select u.username from users u" , nativeQuery = true)
List<String> findByUsername();

Dynamic like query in spring data jpa

Can a dynamic query be written in spring data rest as follows. If not then how to achieve a similar functionality:
#Query("select s from Screen s where s.#searchColumn like:searchValue%")
#RestResource(path="byString")
Page findAll(
#Param("searchColumn") String searchColumn,
#Param("searchValue") String searchValue,
Pageable pageable);
Solved
Repo
#Query("select o from Screen o where "
+ "(o.screenName like :val% and :prop = 'screenName') or "
+ "(o.address like :val% and :prop = 'address')")
#RestResource(path="byString")
Page findAll(
#Param("prop") String prop,
#Param("val") String val,
Pageable pageable);
Query:
/api/screens/search/byString?prop=address&val=a
Tested it with prop=address as well as prop=screenName. Working :)
No. Spring Data JPA support only entityName variables inside SpEL based query templates
For dynamic queries use:
Specifications
Query by Example
Querydsl Extension

Injecting JSON parameter in nativeQuery of Spring JPA

I have a table with a JSONB column. In my project I am using Spring JPA and to query that column I want to use nativeQuery. My problem is to inject varibale into the query like below:
#Query(nativeQuery = true, value = "SELECT * FROM items WHERE item_json -> 'attributes' #> '{\"Param1\": \"" + :param + "\"}' ")
List<Items> findByParameter(#Param("param") String param);
The above query does not work as param is not considered as JPA parameter. I am wondering if anyone knows how to do this? or I should do it in another way?

How to write JPA Query to the equivalent mysql query

I want to write equivalent JPA query to the following mysql query
select active_package,sum(duration),sum(charge),count(*)
from User
where call_type="MO"
and start_date between '2012-02-01' and '2012-02-09'
group by active_package;
For JPA Query the corresponding Attributes are below.
activePackage,callType,duration,charge,startDate
Entity class is User.
I want to use the createQuery() of JPA.
Can any one tell me or give me the link where can i find the solution for this.
Try this one, it should work, if not, please comment, we will get it work :).
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Tuple> cq = cb.createQuery(Tuple.class);
Root<User> entity = cq.from(User.class);
cq.multiselect(entity.get("activePackage"),
cb.sum(entity.get("duration").as(Long.class)),
cb.sum(entity.get("charge").as(Double.class),
cb.count(entity).as(Long.class)));
cq.where(cb.equal(entity.get("callType"), "MO"),
cb.between(entity.get("startDate").as(Date.class),
new Date(), new Date()));
cq.groupBy(entity.get("activePackage"));
List<Tuple> resultList = entityManager.createQuery(cq).getResultList();
for (Tuple result : resultList) {
System.out.println(result.get(0) + " " + result.get(1)
+ " " + result.get(2) + " " + result.get(3));
}
Also if you want to filter only by date, but have timestamp in your model, you can check this Compare date's date part only with Timestamp in Hibernate answer.
Also JPA provides constructing result classes as return values, so you can group your columns. Read more.