In my Spring Data repository I (have to) use custom queries using the #Query annotation. I know I can limit the number of results in a named query like that
Iterable<Person> findFirst5OrderByLastName()
or that it is possible to limit the number of results by passing a pageable like that
Iterable<Person> findByLastName(String lastName, Pageable pageable)
But is it possible to achieve the same when using a custom #Query annotation?
TIA
EDIT
as I see my question is a little confusing, some clearification:
What I want is to limit the number of the results I get, when using a custom query, so that I neither
1) need to specify the result-size through a pageable
2) need to use a named query to specify the result-size
In fact I want the limitation of the number of results to be completely transparent when invoking method (hence not passing a Pageable) and to not rely on the naming-scheme of Spring Data (as the meaning/function of the method is best conveyed through a custom name)
You can try this:
#Entity
#Table(name = "persons")
public class Person {
//...
}
#Query(value = "select * from persons limit 50", nativeQuery = true)
List<Person> getFirst50();
Don't forget to check whether your SQL server supports the limit keyword.
Of course you can use #Query to order a result, it is an JPQL query e.g.
#Query("SELECT u FROM User u ORDER BY u.name ASC")
Further sorting can be done be either providing a PageRequest or using Sort directly.
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.sorting
I would suggest to add "By" but without parameter, it would work:
List<Person> findTop100By();
You need to extend PagingAndSortingRepository
and add method
Page<Person> listAllByPage(Pageable pageable)
See the example
Hello you can try this
#Query("...")
List<YourDTO>getData(Pageable pageable)
In your serviceImpl
List<YourDTO> getData(){
int limit=10;
Pageable pageable = PageRequest.of(0, limit);
return this.repo.getData(pageable);
}
You should avoid nativeQuery
Related
I'm looking for a solution for following problem -
i want to create a #Query like this:
#Query("select s from Student s where s.name like %?1% and s.surname like %?1%")
because I need to be able to show student with given name and surname. I was able to make it sort of work, because when I change and with or, the query shows entries with either given name or given surname, but as soon as i change it back to and nothing shows.
interface StudentRepository extends JpaRepository<Student, Integer> {
#Query("select s from Student s where s.name like %?1% and s.surname like %?1%")
Page<Student> findByNameAndSurname( String name, String surname, Pageable pageable);
}
#GetMapping
Page<Student> getAllStudents(#RequestParam Optional<String> name,
#RequestParam Optional<String> surname,
#RequestParam Optional<Integer> page,
#RequestParam Optional<String> sortBy) {
return repository.findByNameAndSurname(name.orElse("_"),
surname.orElse("_"),
PageRequest.of(
page.orElse(0), 5,
Sort.Direction.ASC, sortBy.orElse("id")));
I also have second question, is it possible to remove this code that shows at the end of JSONs while using pageRequest - I would like only the Student entries to show without this if possible
{"content":[],"pageable":{"sort":{"empty":false,"sorted":true,"unsorted":false},"offset":0,"pageNumber":0,"pageSize":5,"unpaged":false,"paged":true},"last":true,"totalPages":0,"totalElements":0,"size":5,"number":0,"sort":{"empty":false,"sorted":true,"unsorted":false},"first":true,"numberOfElements":0,"empty":true}
I tried using native query in #Query annotation, I also tried modifying the query itself, using some concat tricks i found online, but nothing works;(
JpaRepository supports the query method so if you want to search the items which contains the place holder values you can do it by just defining the method like below.
Page<Student> findByStartingWithFirstNameAndStartingWithSurname();
?1 is for the first parameter name so you must replace your second ?1 with ?2 to use the parameter surname.
For your second question, you can map your page into a list:
repository.findByNameAndSurname(name.orElse("_"),
surname.orElse("_"),
PageRequest.of(
page.orElse(0), 5,
Sort.Direction.ASC, sortBy.orElse("id"))).stream().toList();
Take a look at your query:
#Query("select s from Student s where s.name like %?1% and s.surname like %?1%")
You have defined two placeholders with ?1 what will result in both placeholders to have the same value. So you're literally searching for someone with the same first and last name, that's why an OR would work here.
I am not familiar with Spring, but reading the following tutorial tells me that you can write your query as follows:
#Query("select s from Student s where s.name like %:firstname% and s.surname like %:lastname%")
You need to bind the parameters with the #Param(var) annotation in your method's parameter list though.
For your last question: You probably shouldn't be returning a Page<Student> from your REST (?) service, but rather a List<Student>.
EDIT: Solutions to this problem are provided in the second and fourth answer regarding this question setMaxResults for Spring-Data-JPA annotation?
Goal: Fetch the largest/smallest element by property z using a Spring Data JPA repository and the Spring Query annotation.
What I have so far
#Query("SELECT xelement FROM x xelement ORDER BY xelement.z")
public List<X> findFirstElement();
Problem: This query fetches all elements (which is not really effective). If I would use the EntityManager direcly, I could set the number of results using
entityManager.setMaxResults(1)
to only get the first element.
Question: How do I specify the maximum number of results using the #Query annotation?
Idea: Is using a PageRequest of size 0 the way to go?
Constraints: I am aware of the "FindFirstBy...." query feature but I want/have to use the #Query annotation.
You can use the limit property of sql just by adding nativeQuery to #Query annotation. However, there is another and a better way of doing this. Pageable class in your repository method will solve your problem without touching your #Query annotation:
#Query(value = "SELECT xelement FROM x xelement ORDER BY xelement.z")
List<X> findFirstElement(Pageable limit);
To set the limit and offset, use should call this repository method as follows:
List<X> xValues = xRepository.findFirstElement(new PageRequest(0, 1));
Here 1 corresponds to the limit which you want.
UPDATE (SPRING DATA 2.0)
Use PageRequest.of(0, 1) instead of new PageRequest(0, 1)
The closest JPA query syntax I can think for your use case is findFirstByZIsNotNullOrderByZAsc. This should eliminate the need to write custom native query.
Try to do this:
#Query(value = "SELECT xelement FROM x xelement ORDER BY xelement.z LIMIT 1",
nativeQuery = true)
The code I use to list all entries of a table is the following:
entityManager.createQuery("SELECT * FROM Person WHERE Cn=?", Entry.class).getResultList();
(I hope it is correct I still don't run the application).
As from title, is it possible to list entries without specifying a query ?
Yes, if you use Criteria.
List<Person> persons = sessionFactory.getCurrentSession().createCriteria(Entry.class)
.add(Restrictions.eq("Cn", "some value")).list();
However, there is other magic. Called Spring Data. In Spring Data that would be
public interface PersonRepository extends JpaRepository<Person, Long> {
List<Person> findByCn(String cn);
}
I have a Spring Data & JPA QueryDSL based project in which I have many repository interfaces extending QueryDslPredicateExecutor like below:
public interface ProductRepository extends JpaRepository<Product, Long>,
QueryDslPredicateExecutor<Product> {
}
I am performing findAll() queries with BooleanExpressions all over my application to fetch data. However I now need to find the distinct results of a query based on a particular column.
I am also using Projections & Custom repositories in some cases to select particular columns based on this post.
Is there a way to select distinct so that I only get the distinct values of a particular column for a query, based on any of the above approaches?
Today I've encountered the same issue and it seems that there's no direct repository approach to solve it.
I ended using Querydsl in order to accomplish what I wanted: being able to use Page<T> findAll(Predicate var1, Pageable var2); using distinct.
A simple snippet:
public Page<LocalizedMessage> findAll(Predicate predicate, Pageable pageable) {
QMessage qMessage = QMessage.message;
Querydsl querydsl = new Querydsl(entityManager, new PathBuilder<>(Message.class, qMessage.getMetadata()));
JPAQuery countQuery = querydsl.createQuery(qMessage).distinct().where(predicate);
JPAQuery query = querydsl.createQuery(qMessage).distinct().where(predicate);
querydsl.applyPagination(pageable, query);
return PageableExecutionUtils.getPage(query.fetch(), pageable, countQuery::fetchCount);
}
This code is based on QuerydslJpaRepository's findAll(Predicate, Pageable) method. I presumed that it could be easy to extend this repository in order to add findAllDistinct methods using JPQLQuery.distinct().
I've filed a feature request at spring-data's JIRA.
Hope this helps someone.
If you use Querydsl queries directly in your repository you can call query.distinct() to get distinct results.
I was looking to see how I could introduce a sort into a Query annotation in a repository method that I have.
I already saw this code in Google and here, but I could not make it works
#Query("find({state:'ACTIVE'}).sort({created:-1}).limit(1)")
Job findOneActiveOldest();
#Query("{ state:'ACTIVE', $orderby: {created:-1}, $limit:1 }")
Job findOneActiveOldest();
I know that with pagination I can make it, but in some cases I don't need paginate, so I was wondering how to make it with Query annotation.
Any suggestion please?
I don't think it is possible to do it with #Query annotation. If you dont need to paginate you can just make your repository method use Sort parameter:
#Query("{ state:'ACTIVE' }")
Job findOneActive(Sort sort);
and use it:
yourRepository.findOneActive(new Sort(Sort.Direction.DESC, "created"))
Just use sort parameter of #Query annotation. 1 = ASC, -1 = DESC
#Query(
value = ...,
sort = "{'details.requestTime': -1}"
)
if you also want to have pagination then use Pageable as method argument instead of Sort. Try below code:
#Query("{ state:'ACTIVE' }")
Job findOneActive(Pageable pageable);
yourRepository.findOneActive(new PageRequest(0, 1, new Sort(Sort.Direction.DESC,"created")));