How to use Specification in custom methods in JPA Repository - spring

Let's say that I have this search repository method:
#Query(value = "SELECT t.a, t.b, t.c, t.d, t.e from Table t where t.a= :param1 and t.e= :param2")
Page<MyObject> search(Long param1, Long param2, Pageable pageable);
I want to apply a Specification into this method like follows :
#Query(value = "SELECT t.a, t.b, t.c, t.d, t.e from Table t where t.a= :param1 and t.e= :param2")
Page<MyObject> search(Long param1, Long param2, Specification specification, Pageable pageable);
Is it possible to make it? Because I'm pretty sure that Specification can only applies on default Spring methods (findAll).

The right answer is no. According JpaSpecificationExecutor you could use Specification object with the following methods:
findOne(#Nullable Specification<T> spec);
findAll(#Nullable Specification<T> spec);
findAll(#Nullable Specification<T> spec, Pageable pageable);
findAll(#Nullable Specification<T> spec, Sort sort);
count(#Nullable Specification<T> spec);

Related

Spring Data JDBC - Pageable on custom Query

On my Project I have a Repository that extends CrudRepository. Inside there I have a custom query:
public interface CustomerRepository extends CrudRepository<Customer, Long> {
#Query("select * from person where firstname = :firstname")
List<Customer> findByFirstname(#Param("firstname") String firstname, Pageable pageable);
}
in my Service-Class I try to put the List in a Pageable - Object like:
... getPageableCustomer(String firstname, Pageable pageable){
// => By using "Sol" I got 90 matching entries
List<Customer> custList = customerRepository.findByFirstname(firstname, pageable);
Page<Customer> custPage = new PageImpl<Customer>(custList, pageable, custList.size());
return custPage;
}
the return value includes the complete List "custList". What would be the best way to get a pageable object with specified offset and size?
One option could be to use
customer.subList(fromIndex, toIndex)
but that feels wrong. Also because of Loading all Data inside the list instead of just getting data by size and offset as parameterized with pageable.
Remark: In case of using Page inside the Repository I ´ll get org.springframework.dao.IncorrectResultSizeDataAccessException: Incorrect result size: expected 1, actual 88
There is also a open Improvement on Jira that could be found here:
https://jira.spring.io/browse/DATAJDBC-554?filter=-3
hope for some help...
I got a response on the JIRA-Issue from Dirk Luijk (Thx Dirk :))
https://jira.spring.io/browse/DATAJDBC-554?filter=-3
interface FooRepository extends PagingAndSortingRepository<FooEntity, Long> {
List<FooEntity> findAllByBar(String bar, Pageable pageable);
Long countAllByBar(String bar);
}
And then combining those 2 queries like this:
List<FooEntity> fooList = repository.findAllByBar("...", pageable);
Long fooTotalCount = repository.countAllByBar("...");
Page<FooEntity> fooPage = PageableExecutionUtils.getPage(fooList, pageable, () -> fooTotalCount);
"the mistake in your workaround is your custom query. In Spring Data JDBC 2.0 you don't need to use that, except for special queries but they won't support pageables."
Possible Parameters could be found:
https://docs.spring.io/spring-data/jdbc/docs/current/reference/html/#jdbc.query-methods
Thx Dirk,
I also find a workaround to get it running with a custom Query. Just use limit, offset and orderBy as additional Parameter like so:
#Query("select * from person where firstname = :name order by :order limit :size offset :offset")
List<Customer> findByFirstNameCustomQuery(#Param("name") String name, Pageable page, #Param("offset") long offset,
#Param("size") long size, #Param("order") String order);
And than change the call inside the Service like:
List<Customer> custList = customerRepository.findByFirstNameCustomQuery(firstname, pageable, ....

How to perform sort with multiple fields on custom query JPQL with Spring Pageable

I am using Spring's Pageable to sort the columns.
A working example is below:
Pageable pageable = PageRequest.of(0, countOfBookData.intValue(), getSortingDirection(sortingOrder), sortingField);
Where sortingOrder = ASC and sortingField = bookName
Here is the query
#Query("SELECT bs FROM BookSummary bs WHERE bs.bookId=:bookId")
List<Books> getBookDetails(#Param("bookId") Integer bookId, Pageable pageable)
But I got stuck when I need to perform this sort on Custom my custom query.
So I have no idea how I can perform the sorting using Pageable for below custom query:
Public List<Tuple> getBookDetails(Integer bookId){
String query = "SELECT book.bookCd as bookCode, "
+ "book.name as bookName"
+ "FROM Book book WHERE book.bookId=:bookId";
return entityManager.createQuery(query , Tuple.class).setParameter("bookId", bookId).getResultList();
}
The same as in the first custom query but using the Projection, for example:
public interface BookDetails {
String getBookCode();
String getBookName();
}
#Query("select b.bookCd as bookCode, b.name as bookName from Book b where b.bookId = ?1")
List<BookDetails> getBookDetails(Integer bookId, Pageable pageable);
Note that projection method names must match with corresponding aliases in the query.
Or without the query:
List<BookDetails> getAllById(Integer bookId, Pageable pageable);

Oracle Parallel Hint on Spring Data JPA Specification

Is it possible to use parallel hint on the spring data jpa specification? org.hibernate.jpa.QueryHints package does not contain PARALLEL hint.
I added a comment like in the example below. But I couldn't see the running query.
Calling find method with specifications:
CarSpecifications carSpecifications = new CarSpecifications(car);
List<Car> carList = carRepository.findAll(carSpecifications, pageable);
Repository:
#Override
public Page<T> findAll(Specification<T> spec, Pageable pageable) {
TypedQuery<T> query = getQuery(spec, pageable);
query.setHint("org.hibernate.comment", "Example Comment");
return pageable == null ? new PageImpl<T>(query.getResultList()) : readPage(query, pageable, spec);
}
or in the interface
#QueryHints({ #QueryHint(name = "org.hibernate.comment", value ="Example Comment") })
Page<T> findAll(Specification<T> spec, Pageable pageable);
Thanks.

How to write a findByCritera1InAndCritera2In using (spring data) CrudRepository with parameters being optional

I'm using spring boot with spring data, specifically the class PagingAndSortingRepository that extends CrudRepository.
I need a query which returns all entries of a table if matches either of the four lists ignoring it when it is null (or empty).
If I use findByTypeInAndLocaleInAndCategoryInAndTagIn and one of the lists is empty, the result is empty as well. So I ended up writing several finders and depending on which lists are empty using a different one. Is it possible to combine this in one finder?
So e.g. if I use findByTypeAndLocale I'd like to match all values of type if the list type is empty.
Happy about any hints.
#Repository
public interface FeedRepository extends PagingAndSortingRepository<FeedEntry, Long>, JpaSpecificationExecutor<FeedEntry> {
public List<FeedEntry> findByGuid(String guid);
public Page<FeedEntry> findAll(Pageable pageable);
public Page<FeedEntry> findByLocale(List<LocaleEnum> type, Pageable pageable);
public Page<FeedEntry> findByType(List<FeedTypeEnum> type, Pageable pageable);
public Page<FeedEntry> findByTypeAndLocale(FeedTypeEnum type, LocaleEnum locale, Pageable pageable);
public Page<FeedEntry> findByTypeInAndLocaleIn(List<FeedTypeEnum> type,List<LocaleEnum> locale, Pageable pageable);
public Page<FeedEntry> findByTypeInAndLocaleInAndCategoryIn(List<FeedTypeEnum> type,List<LocaleEnum> locale, List<String> category, Pageable pageable);
public Page<FeedEntry> findByTypeInAndLocaleInAndTagIn(List<FeedTypeEnum> type,List<LocaleEnum> locale, List<String> tag, Pageable pageable);
public Page<FeedEntry> findByTypeInAndLocaleInAndCategoryInAndTagIn(List<FeedTypeEnum> type,List<LocaleEnum> locale, List<String> category, List<String> tag, Pageable pageable);
}
You cannot do it as you are doing. If the list is empty means there isn't any value which matches with your condition query.
To do what you are looking for you need to do it with QBE (Query By example) which is compatible with CrudRepository
QBE doc
Why? You need a dynamic query and as the doc says:
Query by Example (QBE) is a user-friendly querying technique with a
simple interface. It allows dynamic query creation and does not
require to write queries containing field names. In fact, Query by
Example does not require to write queries using store-specific query
languages at all.
An example of the doc:
public interface PersonRepository extends JpaRepository<Person, String> { … }
public class PersonService {
#Autowired PersonRepository personRepository;
public List<Person> findPeople(Person probe) {
return personRepository.findAll(Example.of(probe));
}
}
**Making example for your case...
I'm affraid it is not possible at the moment.
IMHO the best way you can achieve your goal is to use Spring Data JPA Specifications (http://docs.spring.io/spring-data/jpa/docs/1.10.2.RELEASE/reference/html/#specifications) and manually check every parameter for not null value...

How to use Or condition in PagingAndSortingRepository

I need to use two or more conditions on different fields in a Repository that extends PagingAndSortingRepository.
For example:
public interface PersonRepository extends PagingAndSortingRepository<Person,String> {
Page<Person> findByCreatedUser(String createdUserId, Pageable pageable);
}
This method should filter by createdUserId=Person.createdUserId or createdUserId=Person.userId.
How can this be done?
Never mind. I found the answer.
Page findByCreatedUserIdOrUserId(String createdUserId, String userId, Pageable pageable);
Just define a method and add the #Query annotation as outlined in the documentation:
public interface PersonRepository extends PagingAndSortingRepository<Person,String> {
#Query("......")
Page<Person> findByCreatedUser(String createdUserId, String userId, Pageable pageable);
}
http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.at-query

Resources