Oracle Parallel Hint on Spring Data JPA Specification - spring

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.

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 use Specification in custom methods in JPA Repository

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);

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);

How can I use Spring's pagination (using Pageable) while writing a dynamic query using QueryDSL?

I am trying to use pagination with QueryDSL - using the com.mysema.querydsl package.
All my Querydsl query types look like this -
#Generated("com.mysema.query.codegen.EntitySerializer")
public class QCountry extends EntityPathBase<Country> {...}
Currently, my repository implementation class looks something like this -
#Override
public Page<Country> findPaginatedCountries(String country, Optional<String> status, Pageable pageable) {
QCountry qCountry= QCountry.someObject;
QActiveCountry qActiveCountry = QActiveCountry.activeCountry;
JPAQuery jpaQuery = new JPAQuery(entityManager);
QueryBase queryBase = jpaQuery.from(qCountry).innerJoin(qActiveCountry).fetch()
.where(qCountry.codeLeft.country.upper().eq(country.toUpperCase()))
.where(qCountry.codeRight.country.upper().eq(country.toUpperCase()));
if(status.isPresent()){
queryBase = queryBase.where(qActiveCountry.id(qCountry.active.id))
.where(qActiveCountry.status.upper().eq(status.get().toUpperCase()));
}
.......}
Now, I want this dynamic query to return a paginated response. I want to use Spring's pagination to do that and not manually set offset, size etc.
I know I can use QueryDslRepositorySupport class - as implemented here - https://github.com/keke77/spring-data-jpa-sample/blob/master/spring-data-jpa/src/main/java/com/gmind7/bakery/employee/EmployeeRepositoryImpl.java
Sample code from the above link -
#Override
public Page<Employees> QFindByOfficeCode(long officeCode, Pageable pageable) {
//JPAQuery query = new JPAQuery(em);
JPQLQuery query = from(QEmployees.employees).where(QEmployees.employees.officeCode.eq(officeCode));
query = super.getQuerydsl().applyPagination(pageable, query);
SearchResults<Employees> entitys = query.listResults(QEmployees.employees);
return new PageImpl<Employees>(entitys.getResults(), pageable, entitys.getTotal());
}
However, to do that -
I need to pass JPQLQuery object to the applyPagination method. How can I do that without changing my code (Ofcourse, the repository class will extend QueryDslRepositorySupport class). Currently, I am using JPAQuery as you can see.
OR
I probably need to change my QueryDSL types by having them extend EntityPath instead of EntityPathBase so that I can use JPQLQuery.from() to generate the query and then use the applyPagination method, which requires a JPQLQuery object. However, my Q classes are extending EntityPathBase class instead. Should I be use com.querydsl package instead of com.mysemsa.querydsl package to generate query types?
OR
Other option is to use the following - http://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/querydsl/QueryDslPredicateExecutor.html#findAll-com.querydsl.core.types.Predicate-org.springframework.data.domain.Pageable-
Code snippet below -
Page<T> page = QueryDslPredicateExecutor.findAll(org.springframework.data.querydsl.Predicate predicate, Pageable pageable)
However, I am making joins between two tables and then filtering results with a where clause (as you can see above in my code). How can I pass a predicate object in the findAll method above? Not sure how to include a join in it.
Please let me know if the problem is not clear, I can add more details.
EDIT: There is a many to one relationship between Country and ActiveCountry.
Country class has an ActiveCountry reference. And we have to do a join between both ids. Is is possible that Country can have null ActiveCountry. Therefore, we want an inner join - only non null values for active country
#ManyToOne
#JoinColumn(name="id")
ActiveCountry active;
Step 1: Annotate the entity class with #QueryEntity
#Entity
#QueryEntity
public class Country {}
This seems to have been addressed already since the question shows Q classes.
Step 2: Have the repository interface extend QueryDslPredicateExecutor
public interface CountryRepository
extends PagingAndSortingRepository<Country, Long>
, QueryDslPredicateExecutor<Country> {
}
Step 3: Invoke the Page<T> findAll(Predicate query, Pageable page) method provided by QueryDslPredicateExecutor
public Page<Country> getCountries(String country, Optional<String> status, Pageable page) {
QCountry root = QCountry.country;
BooleanExpression query = root.codeLeft.country.equalsIgnoreCase(country);
query = query.and(root.codeRight.country.equalsIgnoreCase(country));
if (status.isPresent()) {
query = query.and(root.active.status.equalsIgnoreCase(status));
}
return countryRepository.findAll(query, page);
}

Spring Data Pageable breaking Spring Data JPA OrderBy

I have a simple JpaRepository with a finder that returns records ordered by a property named "number" in descending order. The "number" property is also the #Id of my entity. This works just fine, however there's thousands of records, so I want to return a Page instead of a List.
#Repository
public interface ReceiptRepository extends JpaRepository<Receipt, BigDecimal> {
#Query
public List<Receipt> findByStorerOrderByNumberDesc(String storer);
}
If I change my finder to something like the following, the sorting no longer works. I've tried using the sort capability of the Pageable argument, but it didn't work. Also removed the OrderByNumberDesc, but same result.
#Repository
public interface ReceiptRepository extends JpaRepository<Receipt, BigDecimal> {
#Query
public Page<Receipt> findByStorerOrderByNumberDesc(String storer, Pageable pageable);
}
EDIT - added controller method
The following is my controller method.
#RequestMapping(method = RequestMethod.GET, produces = {"application/json"})
public PagedResources<Receipt> receipts(Pageable pageable, PagedResourcesAssembler assembler) {
Page<Receipt> receipts = receiptRepository.findByStorer("003845", pageable);
return assembler.toResource(receipts, receiptResourceAssembler);
}
I feel I'm missing something very basic here.
I'm using Spring Data JPA 1.5.2 and Commons 1.7.2.
Thanks :)
Add the sort to your Pageable when you create it:
e.g.
Pageable pageable ...;
pageable.getSort().and(new Sort(Direction.ASC, "prop1", "prop1"));
or in Spring MVC you can do:
#RequestMapping(method = RequestMethod.GET, produces = {"application/json"})
public PagedResources<Receipt> receipts(#PageableDefaults(sort = { "x",
"y", "z" }, value = 10)Pageable pageable, PagedResourcesAssembler assembler) {
Page<Receipt> receipts = receiptRepository.findByStorer("003845", pageable);
return assembler.toResource(receipts, receiptResourceAssembler);
}

Resources