I have these 3 independent table i.e Student, Teacher and Subject. Independent here refers that there is no relation in these tables.
I want the count of all these tables . SQL query looks like -
SELECT
(SELECT COUNT(*) FROM Student as ST,
(SELECT COUNT(*) FROM Teacher as TE,
(SELECT COUNT(*) FROM Subject as SU
Now I want to map this result into dto .
The DTO looks like
public class CountDto{
Integer student;
Integer teacher;
Integer subject;
}
The repository call looks like -
#Query(value = "SELECT\r\n"
+ " (SELECT COUNT(*) FROM Student) as ST, \r\n"
+ " (SELECT COUNT(*) FROM Teacher) as TE,\r\n"
+ " (SELECT COUNT(*) FROM Subject) as SU", nativeQuery = true)
public CountDto getCount();
While calling this function I get following error stating
"message": "Failed to convert from type [java.lang.Object[]] to type [com.rbl.mdm.dto.CountDto ] for value '{16, 16 , 34}'; nested exception is org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.lang.Integer] to type [com.rbl.mdm.dto.CountDto]"
How should I convert my response to desired DTO ?
You can declare CountDto as a public interface and it should work. It's called a Projection in terms of Spring. Or you can use SqlResultSetMapping or ConstructorResult along with your class.
you don't have to implement it by any entity class, just create it like an independent interface even within the repository file:
public interface StudentRepository extends CrudRepository<Student, Long> {
#Query(value = "SELECT\r\n"
+ " (SELECT COUNT(*) FROM Student) as ST, \r\n"
+ " (SELECT COUNT(*) FROM Teacher) as TE,\r\n"
+ " (SELECT COUNT(*) FROM Subject) as SU", nativeQuery = true)
Counts getCount();
public static interface Counts {
Integer getST();
Integer getTE();
Integer getSU();
}
}
So here is the answer to do -
The DTO will look like
public CountDto{
private Integer studentTotal;
private Integer teacherTota;
private Integer subjectTotal;
}
The repository call -
#Query(value = "SELECT\r\n"
+ " (SELECT COUNT(*) FROM Student) as ST, \r\n"
+ " (SELECT COUNT(*) FROM Teacher) as TE,\r\n"
+ " (SELECT COUNT(*) FROM Subject) as SU", nativeQuery = true)
public Map<String,Integer> getCount();
Finally the serviceImpl--
public CountDto getCount{
CountDto CountValue = new CountDto();
Map<String,Integer> map = repository.getCount();
for (Map.Entry<String,Integer> entry : map.entrySet()) {
if(entry.getKey().equals("ST"))
CountValue.setStudentTotal( entry.getValue());
if(entry.getKey().equals("TE"))
CountValue.setTeacherTotal( entry.getValue());
if(entry.getKey().equals("SU"))
CountValue.setSubjectTotal( entry.getValue());
}
return CountValue ;
}
But the solution seems quite complex to me. Any simpler approach required.
In pure Hibernate/JPA usage this is a simple dynamic-instantiation query (what JPA calls a "constructor result"):
select new CountDTO(
(SELECT COUNT(*) FROM Student) as ST,
...
)
No idea here about Spring, though a word of warning.. in trying to be useful, it often "gets in the way". Not sure that is the case here... Have you tried straight Hibernate/JPA?
Related
Hi what I am trying to achieve is to get SQL native query result map into my DTO in java spring jpa repository, how do I do this properly? I try several code, but it does not work, here is what I tried:
First try :
#Repository
public interface StockRepository extends RevisionRepository<Stock, Long, Integer>, JpaRepository<Stock, Long> {
#Query(value = "SELECT stock_akhir.product_id AS productId, stock_akhir.product_code AS productCode, SUM(stock_akhir.qty) as stockAkhir "
+ "FROM book_stock stock_akhir "
+ "where warehouse_code = (:warehouseCode) "
+ "AND product_code IN (:productCodes) "
+ "GROUP BY product_id, product_code, warehouse_id, warehouse_code", nativeQuery = true)
List<StockAkhirDto> findStockAkhirPerProductIn(#Param("warehouseCode") String warehouseCode, #Param("productCodes") Set<String> productCode);
}
once I execute the function, I got this error:
No converter found capable of converting from type
[org.springframework.data.jpa.repository.query.AbstractJpaQuery$TupleConverter$TupleBackedMap]
to type [com.b2bwarehouse.Dto.RequestDto.StockDto.StockAkhirDto]
Second try :
#Repository
public interface StockRepository extends RevisionRepository<Stock, Long, Integer>, JpaRepository<Stock, Long> {
#Query(value = "SELECT new com.b2bwarehouse.Dto.RequestDto.StockDto.StockAkhirDto(stock_akhir.product_id AS productId, stock_akhir.product_code AS productCode, SUM(stock_akhir.qty) as stockAkhir) "
+ "FROM book_stock stock_akhir "
+ "where warehouse_code = (:warehouseCode) "
+ "AND product_code IN (:productCodes) "
+ "GROUP BY product_id, product_code, warehouse_id, warehouse_code", nativeQuery = true)
List<StockAkhirDto> findStockAkhirPerProductIn(#Param("warehouseCode") String warehouseCode, #Param("productCodes") Set<String> productCode);
}
in second here is the error:
could not extract ResultSet; SQL [n/a]; nested exception is
org.hibernate.exception.SQLGrammarException: could not extract
ResultSet
below is my DTO:
#Data
#AllArgsConstructor
#NoArgsConstructor
public class StockAkhirDto {
private Long productId;
private String productCode;
private Integer stockAkhir;
}
How should I correct my code? So, can I get the result into my DTO?
You can define the following named native query with appropriate sql result set mapping:
import javax.persistence.NamedNativeQuery;
import javax.persistence.SqlResultSetMapping;
import javax.persistence.ConstructorResult;
import javax.persistence.ColumnResult;
#Entity
#NamedNativeQuery(
name = "find_stock_akhir_dto",
query =
"SELECT " +
" stock_akhir.product_id AS productId, " +
" stock_akhir.product_code AS productCode, " +
" SUM(stock_akhir.qty) as stockAkhir " +
"FROM book_stock stock_akhir " +
"where warehouse_code = :warehouseCode " +
" AND product_code IN :productCodes " +
"GROUP BY product_id, product_code, warehouse_id, warehouse_code",
resultSetMapping = "stock_akhir_dto"
)
#SqlResultSetMapping(
name = "stock_akhir_dto",
classes = #ConstructorResult(
targetClass = StockAkhirDto.class,
columns = {
#ColumnResult(name = "productId", type = Long.class),
#ColumnResult(name = "productCode", type = String.class),
#ColumnResult(name = "stockAkhir", type = Integer.class)
}
)
)
public class SomeEntity
{
}
and then use it:
#Repository
public interface StockRepository extends RevisionRepository<Stock, Long, Integer>, JpaRepository<Stock, Long> {
#Query(name = "find_stock_akhir_dto", nativeQuery = true)
List<StockAkhirDto> findStockAkhirPerProductIn(
#Param("warehouseCode") String warehouseCode,
#Param("productCodes") Set<String> productCode
);
}
i find a way which is not usual, but i find data type called "Tuple" when i try to use QueryDsl to solved this problem, but i won't recommend QueryDsl if you are just getting started just like me. Lets focus on how i do it with "Tuple"
i changed my return type to Tuple, here is how my repository looked like :
#Repository
public interface StockRepository extends RevisionRepository<Stock, Long, Integer>, JpaRepository<Stock, Long> {
#Query(value = "SELECT stock_akhir.product_id AS productId, stock_akhir.product_code AS productCode, SUM(stock_akhir.qty) as stockAkhir "
+ "FROM book_stock stock_akhir "
+ "where warehouse_code = (:warehouseCode) "
+ "AND product_code IN (:productCodes) "
+ "GROUP BY product_id, product_code, warehouse_id, warehouse_code", nativeQuery = true)
List<Tuple> findStockAkhirPerProductIn(#Param("warehouseCode") String warehouseCode, #Param("productCodes") Set<String> productCode);
}
and then here in my service class, since it's returned as Tuple, i have to map the column one by one manually, here is my service function looked like :
public List<StockTotalResponseDto> findStocktotal() {
List<Tuple> stockTotalTuples = stockRepository.findStocktotal();
List<StockTotalResponseDto> stockTotalDto = stockTotalTuples.stream()
.map(t -> new StockTotalResponseDto(
t.get(0, String.class),
t.get(1, String.class),
t.get(2, BigInteger.class)
))
.collect(Collectors.toList());
return stockTotalDto;
}
the column field start with 0, in this way i can keep my query neat at Repository level. But i will accept SternK answer as the accepted answer because that way worked too, i will keep my answer here if someone need something like this
Create standard native #Query
#Query(value = "select id, age, name FROM Person WHERE age=?1", nativeQuery=true)
List<PersonView> getPersonsByAge(int age);
and an interface
public interface PersonView {
Long getId();
Integer getAge();
String getName();
}
columns are matched by order (not by names).
In this way, you have a native query, no entities and not too much boiler plate code (aka many annotations).
However, resulting views (Jdk proxy etc.) are very slow in access, i had some code doing some grouping over a stream, and it's 10x !! slower than with standard DTO/Pojos !
so at the end, I don't use nativeQuery anymore, but:
SELECT new com.my_project.myDTO(p.id, p.age, p.name) .....
The second variant is pretty close. You just have to remove the aliases for the constructor expression:
new com.b2bwarehouse.Dto.RequestDto.StockDto.StockAkhirDto(
stock_akhir.product_id,
stock_akhir.product_code,
SUM(stock_akhir.qty)
)
should work.
Another valid option based on Sternk answer woul be as follows
You can define the following named native query with appropriate sql result set mapping:
resources/META-INF/orm.xml
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_2_0.xsd"
version="2.0">
<named-native-query name="find_stock_akhir_dto" result-class="com.fullyqualified.name.SomeEntity"
result-set-mapping="stock_akhir_dto">
<query><![CDATA[
SELECT
stock_akhir.product_id AS productId,
stock_akhir.product_code AS productCode,
SUM(stock_akhir.qty) as stockAkhir
FROM book_stock stock_akhir
where warehouse_code = :warehouseCode
AND product_code IN :productCodes
GROUP BY product_id, product_code, warehouse_id, warehouse_code]]></query>
</named-native-query>
</entity-mappings>
import javax.persistence.NamedNativeQuery;
import javax.persistence.SqlResultSetMapping;
import javax.persistence.ConstructorResult;
import javax.persistence.ColumnResult;
#Entity
#SqlResultSetMapping(
name = "stock_akhir_dto",
classes = #ConstructorResult(
targetClass = StockAkhirDto.class,
columns = {
#ColumnResult(name = "productId", type = Long.class),
#ColumnResult(name = "productCode", type = String.class),
#ColumnResult(name = "stockAkhir", type = Integer.class)
}
)
)
public class SomeEntity
{
}
and then use it:
#Repository
public interface StockRepository extends RevisionRepository<Stock, Long, Integer>, JpaRepository<Stock, Long> {
#Query(name = "find_stock_akhir_dto", nativeQuery = true)
List<StockAkhirDto> findStockAkhirPerProductIn(
#Param("warehouseCode") String warehouseCode,
#Param("productCodes") Set<String> productCode
);
}
I have a procedure written in database. my_procedure(val1, val2)
So, lets say I have a database query like this:
select field1 as fieldName, field2 as fieldId
(select * from mydb.my_procedure(id)) as aValue // A procedure call
from mydb.my_table
I want to convert this to Spring's Data JPA #Query. Something like this:
#Query (" HERE I WANT THE ABOVE QUERY TO IMPLEMENT")
public List<MyTable> getDetails ()
Are we allowed to do this?
UPDATE
For example I have below query which I want to convert.
select id, name, roll,
(select * from db.calculate_fee (date, id)) fee
from Student
where id = 1 AND roll = 5
I want to do something like
#Query("SELECT student, (select * from db.calculate_fee (date, id) fee FROM Student student "
+ "WHERE student.id=:id, "
+ "AND student.name=:roll")
public List<Student> getDetails(#Param("id") Integer id, #Param("roll") Integer roll);
Is there anyway to do this?
Have you tried it with a native query?
#Query(nativeQuery = true, value = "select field1 as fieldName, field2 as fieldId...")
List<MyTable> getDetails();
(by the way, public is not needed for 'getDetails' as Repositories are interfaces)
#NamedStoredProcedureQueries({
#NamedStoredProcedureQuery(name = "getAllEmployees",
procedureName = "get_all_employees",
resultClasses = Employees.class)
})
#Procedure(name = "getAllEmployees")
List<Employees> getAllEmployees();
Complete tutorial
I have a interface implementing JPARepository and have three methods, one of them is having a custom #Query.
public interface PersonRepository extends JpaRepository<Person, Long> {
List<Person> getPersonBycountryCode(String countryCode);
List<Person> findByCountryCodeAndCity(String string,String city);
#Query(value = "SELECT person.firstName as firstName, person.lastName as lastName, person.countryCode as country, person.city as city,"
+ " SQRT(POWER((69.1 * (person.age - :age )) , 2 )"
+ " + POWER((53 * (person.experience - :experience )), 2)) as eligibility"
+ " FROM Person person"
+ " ORDER BY eligibility ASC")
List<PersonDetailsDto> findPersonDetailsByEligibility(
#Param("age") BigDecimal age,
#Param("experience") BigDecimal experience,
Pageable pageable
);
}
Problem is: method with #Query does not return list of PersonDetailsDto but return list of list of strings (List<List<String>>).
PersonDetailsDto is a POJO class with all the variables described in a query output (firstName, lastName, country, city, eligibility) and also a constructor with all the variables as Parameters. Other two methods does return list of Person object.
Any idea?
Actually JpaRepository<Person, Long> means that, you can use only Person as your dto in jpa repository methods.
For your solution you can just define your dto interface inside the repository :
public interface PersonRepository extends JpaRepository<Person, Long> {
List<Person> getPersonBycountryCode(String countryCode);
List<Person> findByCountryCodeAndCity(String string,String city);
#Query(value = "SELECT person.firstName as firstName, person.lastName as lastName, person.countryCode as country, person.city as city,"
+ " SQRT(POWER((69.1 * (person.age - :age )) , 2 )"
+ " + POWER((53 * (person.experience - :experience )), 2)) as eligibility"
+ " FROM Person person"
+ " ORDER BY eligibility ASC")
List<PersonDetailsDto> findPersonDetailsByEligibility(
#Param("age") BigDecimal age,
#Param("experience") BigDecimal experience,
Pageable pageable
);
//define the interface here
public interface PersonDetailsDto{
public String getFirstName();
public String getLastName();
public String getCountry();
public String getCity();
public Integer getEligibility();
}
}
If I am not wrong the idea behind JPA not looking for specific fields is that is cost (efficiency wise) the same to bring one column or all columns from one row of the table.But to solve your problem you can set nativeQuery = true in the #Query annotation from a Repository class like this:
public static final String FIND_SOMETHING = "SELECT somethingId, somethingName FROM something";
#Query(FIND_SOMETHING, nativeQuery = true)
public List<Object[]> findSomethings();
I hope this will help you to resolve your problem.
You can use new keyword in query of #Query. And make sure you have the appropriate constructor for PersonDetailsDto and also change package name.
#Query(value = "SELECT new com.company.PersonDetailsDto(person.firstName, person.lastName, person.countryCode , person.city ,"
+ " SQRT(POWER((69.1 * (person.age - :age )) , 2 )"
+ " + POWER((53 * (person.experience - :experience )), 2)) "
+ " FROM Person person"
+ " ORDER BY eligibility ASC")
List<PersonDetailsDto> findPersonDetailsByEligibility(
#Param("age") BigDecimal age,
#Param("experience") BigDecimal experience,
Pageable pageable
);
Similar question's answer.
just call it by its alias, it worked for me like that
ex :
#Query(value = "SELECT person FROM Person person"
+ " ORDER BY eligibility ASC")
List<PersonDetailsDto> findPersonDetailsByEligibility(
#Param("age") BigDecimal age,
#Param("experience") BigDecimal experience,
Pageable pageable
);
I am using Spring Data JPA repositories (1.7.2) and I am typically facing the following scenario:
entities have lazy-loaded collections
those collections are sometimes eagerly fetched (via JPAQL fetch join)
repositories often return Page<Foo> instead of List<Foo>
I need to provide countQuery to every #Query that uses fetch joins on a repository that returns a Page. This issue has been discussed in this StackOverflow question
My typical repository method looks like this:
#Query(value = "SELECT e FROM Employee e LEFT JOIN FETCH e.addresses a " +
"WHERE e.company.id = :companyId " +
"AND e.deleted = false " +
"AND e.primaryAddress.deleted = false " +
"ORDER BY e.id, a.id",
countQuery="SELECT count(e) FROM Employee e WHERE e.companyId = :companyId AND e.deleted = false AND e.primaryAddress.deleted = false"
)
Page<Employee> findAllEmployeesWithAddressesForCompany(#Param("companyId") long companyId, Pageable pageable);
Obviously, it's not very DRY. You can tell that I am repeating all of the conditions in both value and countQuery parameters. How do I stay DRY here?
You could do something like this
public interface MyRepository extends JpaRepository {
public static final String WHERE_PART = "e.companyId = :companyId AND e.deleted = false AND e.primaryAddress.deleted = false ";
#Query(value = "SELECT e FROM Employee e LEFT JOIN FETCH e.addresses a " +
"WHERE " + MyRepository.WHERE_PART
"ORDER BY e.id, a.id",
countQuery="SELECT count(e) FROM Employee e WHERE " + MyRepository.WHERE_PART
)
Page<Employee> findAllEmployeesWithAddressesForCompany(#Param("companyId") long companyId, Pageable pageable);
I'm using Spring Data JPA, and when I use #Query to to define a query WITHOUT Pageable, it works:
public interface UrnMappingRepository extends JpaRepository<UrnMapping, Long> {
#Query(value = "select * from internal_uddi where urn like %?1% or contact like %?1%",
nativeQuery = true)
List<UrnMapping> fullTextSearch(String text);
}
But if I add the second param Pageable, the #Query will NOT work, and Spring will parse the method's name, then throw the exception No property full found. Is this a bug?
public interface UrnMappingRepository extends JpaRepository<UrnMapping, Long> {
#Query(value = "select * from internal_uddi where urn like %?1% or contact like %?1%",
nativeQuery = true)
Page<UrnMapping> fullTextSearch(String text, Pageable pageable);
}
You can use pagination with a native query. It is documented here: Spring Data JPA - Reference Documentation
"You can however use native queries for pagination by specifying the count query yourself:
Example 59. Declare native count queries for pagination at the query method using #Query"
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);
}
A similar question was asked on the Spring forums, where it was pointed out that to apply pagination, a second subquery must be derived. Because the subquery is referring to the same fields, you need to ensure that your query uses aliases for the entities/tables it refers to. This means that where you wrote:
select * from internal_uddi where urn like
You should instead have:
select * from internal_uddi iu where iu.urn like ...
Considering that the UrnMapping class is mapped to the internal_uddi table, I would suggest this:
#Repository
public interface UrnMappingRepository extends JpaRepository<UrnMapping, Long> {
#Query(value = "select iu from UrnMapping iu where iu.urn like %:text% or iu.contact like %:text%")
Page<UrnMapping> fullTextSearch(#Param("text") String text, Pageable pageable);
}
Please note that you might have to turn off native queries with dynamic requests.
With #Query , we can use pagination as well where you need to pass object of Pageable class at end of JPA method
For example:
Pageable pageableRequest = new PageRequest(page, size, Sort.Direction.DESC, rollNo);
Where,
page = index of page (index start from zero)
size = No. of records
Sort.Direction = Sorting as per rollNo
rollNo = Field in User class
UserRepository repo
repo.findByFirstname("John", pageableRequest);
public interface UserRepository extends JpaRepository<User, Long> {
#Query(value = "SELECT * FROM USER WHERE FIRSTNAME = :firstname)
Page<User> findByLastname(#Param("firstname") String firstname, Pageable pageable);
}
Please reference :Spring Data JPA #Query, if you are using Spring Data JPA version 2.0.4 and later. Sample like below:
#Query(value = "SELECT u FROM User u ORDER BY id")
Page<User> findAllUsersWithPagination(Pageable pageable);
Declare native count queries for pagination at the query method by using #Query
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);
}
Hope this helps
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods
Rewrite your query to:
select iu from internal_uddi iu where iu.urn....
description: http://forum.spring.io/forum/spring-projects/data/126415-is-it-possible-to-use-query-and-pageable?p=611398#post611398
I found it works different among different jpa versions, for debug, you'd better add this configurations to show generated sql, it will save your time a lot !
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
for spring boot 2.1.6.RELEASE, it works good!
Sort sort = new Sort(Sort.Direction.DESC, "column_name");
int pageNumber = 3, pageSize = 5;
Pageable pageable = PageRequest.of(pageNumber - 1, pageSize, sort);
#Query(value = "select * from integrity_score_view " +
"where (?1 is null or data_hour >= ?1 ) " +
"and (?2 is null or data_hour <= ?2 ) " +
"and (?3 is null or ?3 = '' or park_no = ?3 ) " +
"group by park_name, data_hour ",
countQuery = "select count(*) from integrity_score_view " +
"where (?1 is null or data_hour >= ?1 ) " +
"and (?2 is null or data_hour <= ?2 ) " +
"and (?3 is null or ?3 = '' or park_no = ?3 ) " +
"group by park_name, data_hour",
nativeQuery = true
)
Page<IntegrityScoreView> queryParkView(Date from, Date to, String parkNo, Pageable pageable);
you DO NOT write order by and limit, it generates the right sql
I had the same issue - without Pageable method works fine.
When added as method parameter - doesn't work.
After playing with DB console and native query support came up to decision that method works like it should. However, only for upper case letters.
Logic of my application was that all names of entity starts from upper case letters.
Playing a little bit with it. And discover that IgnoreCase at method name do the "magic" and here is working solution:
public interface EmployeeRepository
extends PagingAndSortingRepository<Employee, Integer> {
Page<Employee> findAllByNameIgnoreCaseStartsWith(String name, Pageable pageable);
}
Where entity looks like:
#Data
#Entity
#Table(name = "tblEmployees")
public class Employee {
#Id
#Column(name = "empID")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#NotEmpty
#Size(min = 2, max = 20)
#Column(name = "empName", length = 25)
private String name;
#Column(name = "empActive")
private Boolean active;
#ManyToOne
#JoinColumn(name = "emp_dpID")
private Department department;
}
When using nativeQuery that is having (nativeQuery = true), you may do the pagination yourself in the query by adding (LIMIT :sizeValue OFFSET :page)
Note:
Your page value passed to this method should be offset * size
Example
#Query(value = "SELECT * FROM person " +
"LIMIT ?1 OFFSET ?2", nativeQuery = true)
Optional<List<TDriverJob>> findPersons(int size, int page);
I tried all above solution and non worked , finally I removed the Sorting from Pagination and it worked
the following tutorial helped me
-> https://www.baeldung.com/spring-data-jpa-query
At this point 4.3. Spring Data JPA Versions Prior to 2.0.4
VERY IMPORTANT to add \ n-- #pageable \ n
Without this I was wrong
Also the pagination setting must be without ordering
PageRequest paginaConf = new PageRequest ((param1 - 1)
, param2);
Finally to convert the Page <Object []>
Page <Object []> list = myQueryofRepo ();
List <XXXModel> lstReturn = myConversor (list.getContent ());
Page <XXXModel> ret = new PageImpl <XXXModel> (lstReturn, pageConf, param2);
This bugged me for a while but I managed with a very smooth solution.
The challenge is JPA did not automatically detect the count query so I resolved to use the countName which according JPA docs Returns the name of the javax.persistence.NamedQuery to be used to execute count queries when pagination is used. Will default to the named query name configured suffixed by .count.
So I created a named query
#NamedNativeQuery(
name = "[queryName].count",
query = [your count query],
resultSetMapping = "[query resultSetMapping name]"
)
}
As indicated, the count query should be suffixed with .count
Count query returns Long so add the resultSetMapping as
#SqlResultSetMapping(
name="[query resultSetMapping name]",
columns={#ColumnResult(name="count", type = Long.class)})
Then in your repository, use the count query as indicated below
#Query(countName ="[queryName].count" , nativeQuery = true)
Page<Object> [mainQuery](...params)
Hope this helps!