How to use #ReqeustBody with the #Query - spring-boot

I'm using a #Query Annotation to SELECT data out of my Database,
but I want to add a Parameter to the SQL Query, to input data from a Request Body.
I don't know how to do that and can't find an example.
For Example, I have an abstract method inside my Repository:
#Query(value= "SELECT * FROM planets WHERE color= :body.getColor()", nativeQuery=true)
Iterable<Planet> getBody(Planet body);
And the Method in the Controller Class would look something like this:
#GetterMapping("/body")
Iterable<Planet> getBody(#ReqeustBody Planet body( { return Repository.getBody(body); }
In Postman I would do something like this:
GET | http://localhost:8080/body | Body | raw | JSON: {"color":"red"}
Obviously this does not work and gives me error:
org.hibernate.QueryException: Named parameter not bound : body.getColor()
My question is how would the syntex be like implementing a ReqeustBody into a #Query?

Do it simple way
#Query(value= "SELECT * FROM planets WHERE color=:color", nativeQuery=true)
Iterable<Planet> getBody(String color);
and pass color instead of Planet
return Repository.getBody(body.getColor())
It is possible to create custom extension to spring repository that would accept some abstract HavingColor object in general, but it requires some boilerplate code (not that much) and is just not worth of an effor (in the result, you will do HavingColor.getColor() anyway but on repository not the caller level).

Related

Is it possible to retrieve data in resources folder instead of repository in particular case?

I have a repository which request my database, but in a particular case, I would like it to get data from a JSON (which have the same structure than my entity).
I've tried :
AOP : before each repository methods, if we are in the particular case, I get the data from a JSON and I can cast it to the correct class (because with AOP i can get the return type of the method). So it's working for methods like :
#Query("SELECT e FROM entity e WHERE e.name = :name")
Entity getAllEntities(String name);
but not with methods like ...
#Query("SELECT n.attribute FROM entity e, nested n WHERE e.name = :name")
String getNestedAttribute(String name);
... because I can't figure out where I could find the data in JSON. Except if you know how I could get the path (for exemple : $['entity']['nested'][0]['attribute']) from an SQL query so I can use this library
Repository populator
On application startup, it replace the data in the database with the value I store in JSON. The problem with it is that I don't want to loose my data ...
I know this post is weird but I don't want to add those data in my database because it would affect to much application ...

Spring data jpa projection could not extract ResultSet

I'm trying to map my entity to projection using the below query but i'm getting error as
Exception : could not extract ResultSet SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet
here is the query
#Query("select rf.rfqID as rfqID,rf.creationDate as creationDate," +
"rf.deadLineDate as deadLineDate,rf.details as details," +
"rf.message as message, rf.rfqDoc as rfqDoc," +
"CASE WHEN (rf.creationDate > CURRENT_DATE) THEN 'open' ELSE 'closed' END as status," +
"rf.rfqMembers as rfqMembers " +
"from RFQ rf where rf.createdBy = ?1")
Page<RfqDto> loadAllRfq(String creator, Pageable pageable);
In my Dto I have an extra status column which I don't want to persist in db and would like to get the status via query
here is my projection interface
public interface RfqDto {
String rfqID();
Date creationDate();
Date deadLineDate();
String details();
String message();
String rfqDoc();
String status();
List<RfqMember> rfqMembers();
}
The root cause of your problem is here:
In my Dto I have an extra status column which I don't want to persist in db and would like to get the status via query
As it's explained in the documentation:
The important bit here is that the properties defined here exactly match properties in the aggregate root.
...
The query execution engine creates proxy instances of that interface at runtime for each element returned and forwards calls to the exposed methods to the target object.
So, you can not use spring data jpa projection for your case. You can not use hibernate/jpa projection as well, because it dose not support collections in row results.
You can try to use Blaze-Persistence Entity Views. See for example this answer.

Spring And Kotlin Query

How can I achieve this query
select *
from table t
where name like '%Ami%'
order by (name = 'Ami') desc, length(col);
(just the sort part)
Using springframework Sort..
What I tried is
Sort.by(Sort.Direction.DESC, "name") // But I need to sort by name = 'Ami'
Sort.by(Sort.Direction.DESC, "name" = 'Ami'") // throws an error
JpaSort.unsafe(Sort.Direction.DESC, "name" = 'Ami'") // throws an error
Looks like the documentation has an example almost identical to your question:
https://docs.spring.io/spring-data/jpa/docs/2.4.5/reference/html/#jpa.query-methods.sorting
However, using Sort together with #Query lets you sneak in
non-path-checked Order instances containing functions within the ORDER
BY clause. This is possible because the Order is appended to the given
query string. By default, Spring Data JPA rejects any Order instance
containing function calls, but you can use JpaSort.unsafe to add
potentially unsafe ordering.

CrudRepository: findBy... but without returning the values of a column

I have a table with columns like this:
ID | A | B | C
I have a class with the attributes ID, A and B but without the attribute C.
I want to implement a CrudRepository find method (for example findAllByA) that takes every row that matches the query but without returning C so the result can be bound to my class.
I know I could have a secondary class with all four arguments and then convert the collection of results to a collection of results of the class I actually want, but I'd rather avoid this.
Simply return an instance of your class from your method.
For example :
public interface YourRepository extends CrudRepository<YourModel, Long> {
#Query("SELECT new com.example.YourClass(e.ID, e.A, e.B) FROM YourEntity e WHERE e.A = ?1")
List<YourClass> findByA(String filter);
}
So the result is bound to your class directly.
I think, mapping is the best choice in this situation. Because YourClass is DTO object and if you change your mind and change the internal structure YourClass in the project, you can only change the mapper code. Yann39's solution is acceptable but if you change the structure of YourClass class, you will need to change every Query related to it.

SimpleJpaRepository Count Query

I've modified an existing RESTful/JDBC application i have to work with new features in Spring 4... specifically the JpaRepository. It will:
1) Retrieve a list of transactions for a specified date. This works fine
2) Retrieve a count of transactions by type for a specified date. This is not working as expected.
The queries are setup similarly, but the actual return types are very different.
I have POJOs for each query
My transactions JPA respository looks like:
public interface MyTransactionsRepository extends JpaRepository<MyTransactions, Long>
//My query works like a charm.
#Query( value = "SELECT * from ACTIVITI_TMP.BATCH_TABLE WHERE TO_CHAR(last_action, 'YYYY-MM-DD') = ?1", nativeQuery = true )
List< MyTransactions > findAllBy_ToChar_LastAction( String lastActionDateString );
This returns a list of MyTransactions objects as expected. Debugging, i see the returned object as ArrayList. Looking inside the elementData, I see that each object is, as expected, a MyTransactions object.
My second repository/query is where i'm having troubles.
public interface MyCountsRepository extends JpaRepository<MyCounts, Long>
#Query( value = "SELECT send_method, COUNT(*) AS counter FROM ACTIVITI_TMP.BATCH_TABLE WHERE TO_CHAR(last_action, 'YYYY-MM-DD') = ?1 GROUP BY send_method ORDER BY send_method", nativeQuery = true )
List<MyCounts> countBy_ToChar_LastAction( String lastActionDateString );
This DOES NOT return List as expected.
The object that holds the returned data was originally defined as List, but when I inspect this object in Eclipse, I see instead that it is holding an ArrayList. Drilling down to the elementData, each object is actually an Object[2]... NOT a MyCounts object.
I've modified the MyCountsRepository query as follows
ArrayList<Object[]> countBy_ToChar_LastAction( String lastActionDateString );
Then, inside my controller class, I create a MyCounts object for each element in List and then return List
This works, but... I don't understand why i have to go thru all this?
I can query a view as easily as a table.
Why doesn't JPA/Hibernate treat this as a simple 2 column table? send_method varchar(x) and count (int or long)
I know there are issues or nuances for how JPA treats queries with counts in them, but i've not seen anything like this referenced.
Many thanks for any help you can provide in clarifying this issue.
Anthony
That is the expected behaviour when you're doing a "group by". It will not map to a specific entity. Only way this might work is if you had a view in your database that summarized the data by send_method and you could map an entity to it.

Resources