How to use method parameter as a plain text in #Query annotation - java

In a JPA repository, I need to do a native query, and in this native query, I need to be able to sort by a column. I want the direction of this sort be determined by one of the parameter of this method.
Here is the code I want to write but doesn't work.
#Repository
interface StudentRepository extends JpaRepository<Student, UUID> {
#Query(
value = "SEELCT * FROM student ORDER BY student_id :sortOrder"
)
Page<Customer> findAllByKeyword(#Param("sortOrder") String sortOrder, Pageable pageable);
}
So sortOrder can be ASC or DSC.

Try
#Query("SELECT c FROM student c ORDER BY c.student_id :sortOrder")

The key point here is need to tell JPA as nativeQuery and Pageble. You can specify as parameter to the #query
example :
#Query(value = "SELECT * FROM USERS WHERE LASTNAME = ?1 ORDER BY ?#{#pageable}", nativeQuery = true)
Page<User> findByLastname(String lastname, Pageable pageable);

Related

How to combine both Specifications and #Query

I have existing page that use a a service with search specifications.
Now, we have update in requirements so I need to use a query with specifications but I'm not sure how.
Below is a code snippets
Repo
#Override
#Query(value = "SELECT * FROM (
SELECT * , ROW_NUMBER() OVER(PARTITION BY field1 ORDER BY field2 DESC) As rn
FROM myTable
) t
WHERE t.rn = 1",nativeQuery = true)
Page<T> findAll(#Nullable Specification specification, Pageable pageable);
Service
repo.findAll(spec,pageable);
But this is not working, I also tried to do a workaround after using default findAll, but it's not working either
Map<field1, T> result = object.get().collect(
Collectors.groupingBy(T::field1,
Collectors.collectingAndThen(
Collectors.maxBy(Comparator.comparingInt(T::field2)),
Optional::get)));

Spring JPA. How to map from #Query(nativeQuery = true) to a POJO [duplicate]

This question already has answers here:
JPA : How to convert a native query result set to POJO class collection
(22 answers)
Closed 2 years ago.
Have a query, let it be
select 1 "colName"
I want to map the result to a POJO type using Spring Data JPA.
Thus the picture is:
public interface MyAwesomeSuperInterface extends CrudRepository {
#Query(value = "select 1 \"colName\"", nativeQuery = true)
List<POJO> something();
}
And the question is HOW to map it to the POJO.class?
Following the common suggestions I assume I'll get:
No, I don't want to change it to JSQL and do a 'new POJO'.
Why? Because I have a complex sql query, which isn't reflectable to JSQL.
No, I will not bring up the query. I merely want to know how to map the upper example to a POJO using Spring Data. Thank you
You can use DTO projection with native queries:
// Projection Interface
public interface UserProjection {
String getName();
String getEmail();
Integer getId();
String getComment();
}
public interface UserRepository extends CrudRepository<User, Integer> {
#Query(value = "select u.name, u.email, c.comment from User u join
Comment c on u.id = c.user_id where u.id in :ids", nativeQuery = true)
List<UserProjection> getUserInterface(List<Integer> ids);
}
This is one example I recently tried with DTO projections. This will Simply map result of the native query to UserProjection.
For more information read: Spring Data JPA Projection support for native queries
It should auto-convert from sql query to pojo you need to define the correct datatype in below example I am using List<User> as the query will return all the data from the table :
#Query("select * from User u")
List<User> findUsers();
If you specify columns then you need to specify constructor in pojo which accepts the same fields.
You can also use parameterized query :
#Query("select * from User u where u.user_id =: userId")
List<User> findUserById(#Param("userId") String userId);
You can also refer to this document :
https://www.baeldung.com/spring-data-jpa-query
it will work hoping for good.

How to write a query using spring jpa to fetch all rows from a database that are matching the string we pass?

Hi I am new to spring boot. I have a table having the following attributes: id,firstName,secondName,lastName.
Now I need to write a query (in repository), to find all those rows in my table whose firstName or secondName or lastName matches with the string I am passing.
eg: if I am passing 'foo' then it should search all the three columns and return those rows having 'foo' in any of them(this is pattern matching).
How can I do that? Thanks in advance.
You can use Like query on multiple column like this way
public interface UserRepository extends PagingAndSortingRepository<User,Long> {
#Query(value="select u from User u where u.firstName = %searchtext% or u.lastName= %searchtext% or u.secondName= %searchtext%")
Page<User> findByAllColumns(#Param("searchtext") String searchtext, Pageable pageable);
}
you can try with the below code
public List<Employee> findByFirstNameIgnoreCaseContainingOrSecondNameIgnoreCaseContainingOrLastNameIgnoreCaseContaining(String firstName,String secondName,String lastName);

What is the LIMIT clause alternative in JPQL?

I'm working with PostgreSQL query implementing in JPQL.
This is a sample native psql query which works fine,
SELECT * FROM students ORDER BY id DESC LIMIT 1;
The same query in JPQL doesnt work,
#Query("SELECT s FROM Students s ORDER BY s.id DESC LIMIT 1")
Students getLastStudentDetails();
seems like LIMIT clause doesn't work in JPQL.
According to JPA documentation we can use setMaxResults/setFirstResult, Can anyone tell me how can I use that in my above query?
You are using JPQL which doesn't support limiting results like this. When using native JPQL you should use setMaxResults to limit the results.
However you are using Spring Data JPA which basically makes it pretty easy to do. See here in the reference guide on how to limit results based on a query. In your case the following, find method would do exactly what you want.
findFirstByOrderById();
You could also use a Pageable argument with your query instead of a LIMIT clause.
#Query("SELECT s FROM Students s ORDER BY s.id DESC")
List<Students> getLastStudentDetails(Pageable pageable);
Then in your calling code do something like this (as explained here in the reference guide).
getLastStudentDetails(PageRequest.of(0,1));
Both should yield the same result, without needing to resort to plain SQL.
As stated in the comments, JPQL does not support the LIMIT keyword.
You can achieve that using the setMaxResults but if what you want is just a single item, then use the getSingleResult - it throws an exception if no item is found.
So, your query would be something like:
TypedQuery<Student> query = entityManager.createQuery("SELECT s FROM Students s ORDER BY s.id DESC", Student.class);
query.setMaxResults(1);
If you want to set a specific start offset, use query.setFirstResult(initPosition); too
Hello for fetching single row and using LIMIT in jpql we can tell the jpql if it's a native query.
( using - nativeQuery=true )
Below is the use
#Query("SELECT s FROM Students s ORDER BY s.id DESC LIMIT 1", nativeQuery=true)
Students getLastStudentDetails();
You can not use Limit in HQL because Limit is database vendor dependent so Hibernate doesn't allow it through HQL query.
A way you can implement is using a subquery:
#Query("FROM Students st WHERE st.id = (SELECT max(s.id) FROM Students s)")
Students getLastStudentDetails();
The correct way is to write your JPA interface method like this
public interface MyRepository extends PagingAndSortingRepository<EntityClass, KeyClass> {
List<EntityClass> findTop100ByOrderByLastModifiedDesc();
}
In the method name, "100" denotes how many rows you want which you would have otherwise put in the limit clause. also "LastModified" is the column which you want to sort by.
PagingAndSortingRepository or CrudRepository, both will work for this.
For the sake of completeness, OP's interface method would be
List<Students> findTop1ByIdDesc();
JPQL does not allow to add the limit keyword to the query generated by the HQL. You would get the following exception.
org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token:
LIMIT near line 1
But don't worry there is an alternative to use the limit keyword in the query generated by the HQL by using the following steps.
Sort.by(sortBy).descending() // fetch the records in descending order
pageSize = 1 // fetch the first record from the descending order result set.
Refer the following service class
Service:
#Autowired
StudentRepository repository;
public List<Student> getLastStudentDetails(Integer pageNo, Integer pageSize, String sortBy)
{
Integer pageNo = 0;
Integer pageSize = 1;
String sortBy = "id";
Pageable paging = PageRequest.of(pageNo, pageSize, Sort.by(sortBy).descending());
Slice<Student> pagedResult = repository.findLastStudent(paging);
return pagedResult.getContent();
}
Your repository interface should implement the PagingAndSortingRepository
Repository:
public interface StudentRepository extends JpaRepository<Student,Long>, PagingAndSortingRepository<Student,Long>{
#Query("select student from Student student")
Slice<Student> findLastStudent(Pageable paging);
}
This will add the limit keyword to you query which you can see in the console. Hope this helps.
Hardcode the pagination(new PageRequest(0, 1)) to achieve fetch only one record.
#QueryHints({ #QueryHint(name = "org.hibernate.cacheable", value = "true") })
#Query("select * from a_table order by a_table_column desc")
List<String> getStringValue(Pageable pageable);
you have to pass new PageRequest(0, 1)to fetch records and from the list fetch the first record.
Here a Top Ten Service (it's a useful example)
REPOSITORY
(In the Query, I parse the score entity to ScoreTo ( DTO class) by a constructor)
#Repository
public interface ScoreRepository extends JpaRepository<Scores, UUID> {
#Query("SELECT new com.example.parameters.model.to.ScoreTo(u.scoreId , u.level, u.userEmail, u.scoreLearningPoints, u.scoreExperiencePoints, u.scoreCommunityPoints, u.scoreTeamworkPoints, u.scoreCommunicationPoints, u.scoreTotalPoints) FROM Scores u "+
"order by u.scoreTotalPoints desc")
List<ScoreTo> findTopScore(Pageable pageable);
}
SERVICE
#Service
public class ScoreService {
#Autowired
private ScoreRepository scoreRepository;
public List<ScoreTo> getTopScores(){
return scoreRepository.findTopScore(PageRequest.of(0,10));
}
}
You can use something like this:
#Repository
public interface ICustomerMasterRepository extends CrudRepository<CustomerMaster, String>
{
#Query(value = "SELECT max(c.customer_id) FROM CustomerMaster c ")
public String getMaxId();
}
As your query is simple, you can use the solution of the accepted answer, naming your query findFirstByOrderById();
But if your query is more complicated, I also found this way without need to use a native query:
#Query("SELECT MAX(s) FROM Students s ORDER BY s.id DESC")
Students getLastStudentDetails();
Here a practical example where the named query method cannot be used.

Spring Data and Native Query with Sorting

In a web project, using spring-data(1.10.4.RELEASE) with a Oracle database, i am trying use a native query with a Sort variable.
public interface UserRepository extends JpaRepository<User, Long> {
#Query(nativeQuery = true,value = "SELECT * FROM USERS WHERE LASTNAME = :lastname #sort")
List<User> findByLastname(#Param("lastname") String lastname, Sort sort);
}
The query launched is:
SELECT * FROM USERS WHERE LASTNAME = 'Lorite' #sort ORDER BY LASTNAME
Like you can see the annotation "#sort" is still there.
I have tried Spring Data and Native Query with pagination but the annotation is there yet and using another syntax like ?#{#sort} or {#sort} the problem persist.
Anything is welcome.
Thanks!
The documentation says:
Note, that we currently don’t support execution of dynamic sorting for native queries as we’d have to manipulate the actual query declared and we cannot do this reliably for native SQL.
Furthermore, this #sort interpolation does not exist
[1] http://docs.spring.io/spring-data/jpa/docs/current/reference/html/
public interface UserRepository extends JpaRepository<User, Long> {
#Query(value = "SELECT * FROM USERS WHERE LASTNAME = ?1",
countQuery = "SELECT count(*) FROM USERS WHERE LASTNAME = ?1",
nativeQuery = true)
Page<User> findByLastname(String lastname, Pageable pageable);
}
Example 64. Declare native count queries for pagination at the query method by using #Query
Native Queries with Spring Data JPA

Categories