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!
Related
I am trying to find out a way to concatenate strings to create a JPA native query. At present I have 3 queries just for having 1 or 2 different words. For example:
String queryAsc = select emp.id,role_id from employee left join roles
on roles.id = emp.role_id
where emp.id = :id
order by employee.created_date asc;
String queryDesc = select emp.id,role_id from employee left join roles
on roles.id = emp.role_id
where emp.id = :id
order by employee.created_date desc;
Just because of the word difference of "asc" vs "desc", I have to write 2 different repository methods with JPA query as:
#Query(value = queryAsc,
countQuery = countToMyEmployees, nativeQuery = true)
Page<Object[]> findMyEmployeesAsc(#Param("id") String id, Pageable pageable);
#Query(value = queryDesc,
countQuery = countToMyEmployees, nativeQuery = true)
Page<Object[]> findMyEmployeesDesc(#Param("id") String id, Pageable pageable);
Is there a way to concatenate two strings in JPA query to avoid this kind of repetition?
Try using Sort from the caller.
if (condition) {
obj.findMyEmployees("123",pageableObject , new Sort("employee.created_date "));
} else {
obj.findMyEmployees("234",pageableObject ,new Sort(Sort.Direction.DESC,"employee.created_date"));
}
And rewrite the query as given below :
String query= select emp.id,role_id from employee left join roles
on roles.id = emp.role_id
where emp.id = :id;
#Query(value = query,
countQuery = countToMyEmployees, nativeQuery = true)
Page<Object[]> findMyEmployees(#Param("id") String id, Pageable pageable, Sort sort);
I have the following piece of code:
#Query(value = "select * from james_mail where encode(header_bytes, 'escape') like '%Message-ID: :messageId%'", nativeQuery = true)
List<JamesMail> findByMessageIdFromHeader(#Param(value = "messageId") String messageId);
The expected behavior is to execute the query with bind parameter (e.g. messageID)
Actual behavior is that the query is executed as it is, without biding
What is the solution for actually biding, or there is an workaround for my problem?
Technology stack:
Spring Boot, JPA, Hibernate
here you are trying to encode header_bytes which is contained table james_mail right
and you want to find rows which contains value matching to messageId and contains Message-ID
#Query(value = "select * from james_mail where encode(header_bytes, 'escape') like '%Message-ID%' and encode(header_bytes, 'escape') like %:messageId%", nativeQuery = true)
List<JamesMail> findByMessageIdFromHeader(#Param(value = "messageId") String messageId);
Try to correct your query in this way:
#Query(value = "select * from james_mail where encode(header_bytes, 'escape') like '%Message-ID: ' || :messageId || '%'", nativeQuery = true)
List<JamesMail> findByMessageIdFromHeader(#Param(value = "messageId") String messageId);
I am facing a problem with my JpaRepository in a spring boot application
I want to perform a simple update query on my database, but it turns out that the native query is quite annoying, please help
public interface ImageRepository extends JpaRepository<Image, Integer> {
#Modifying
#Transactional
#Query(value = "UPDATE image SET path =(0?), status = (1?) WHERE Id = (2?)", nativeQuery = true)
void update(String path ,String status,int Id);
}
the code above returns the following error message
com.microsoft.sqlserver.jdbc.SQLServerException: Incorrect syntax near '#P0'.
I have tried to change SQL dialect to
org.hibernate.dialect.SQLServer2008Dialect
org.hibernate.dialect.SQLServer2012Dialect
respectively and non of them worked.
I tried also to write the query in a different way which does not give me an error but it does not update the fields. it can detect the integer value from the method but it will set the string values to an emply value:
#Query(value = "UPDATE image SET physical_path =(0), status = (1) WHERE Id = (2)", nativeQuery = true)
If anyone has faced the same issue please support
Frame the query like this :
#Query(value = "UPDATE image i SET path =:path, status = :status WHERE i.Id = :Id", nativeQuery = true)
void update(#Param("path") String path , #Param("status") String status, #Param("Id") int Id);
For positional parameters :
#Query(value = "UPDATE image i SET path = ?1, status = ?2 WHERE i.Id = ?3", nativeQuery = true)
void update(String path , String status, int Id);
From the Spring Data JPA - Reference you can see that the parameters (in the way you want to use them) are defined like -> ?1, ?2 etc..
Also, please keep in mind that the JPQL syntax is slightly different than plain sql.
#Modifying
#Query("update Image i set i.path = ?1 where i.status = ?2 where i.id = ?3")
void update(String path, String status, int id);
I'm trying to do a query, using mySql fullText index "match against" syntax with a paegable.
I changed the spring-boot version from 1.5.4.RELEASE to 2.0.0m7 to use spring-data-jpa version 2.0.2.RELEASE, because in the earlier spring-data-jpa version, a native query with a countQuery wasn't working.
I've fixed a couple of problems, using the solutions here and here.
The current problem is the following error:
javax.servlet.ServletException: org.springframework.orm.jpa.JpaSystemException: could not execute query; nested exception is org.hibernate.exception.GenericJDBCException: could not execute query
...
Caused by: java.sql.SQLException: Parameter index out of range (2 > number of parameters, which is 1).
And here is the code
#Query( value = "SELECT Distinct u.* " +
"FROM user AS u " +
"WHERE MATCH(u.name, u.email) against(:filterValue) " +
"ORDER BY u.id \n#pageable\n#",
countQuery = "SELECT count(Distinct u.id) " +
"FROM user AS u " +
"WHERE MATCH(u.name, u.email) against(:filterValue) " +
"ORDER BY u.id \n#pageable\n#",
nativeQuery = true)
Page<User> foo(#Param("filterValue") String filterValue, Pageable pageable);
If I try to set pageable as a param too, the same error occurs.
Any thoughts?
You don't have to include the pageable explicitly in your query.
See the example from the reference documentation.
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);
}
I strongly recommend you upgrade to the current release version of Spring Data instead of the milestone build.
Try to put Pageable on first place:
Page<User> foo(Pageable pageable, #Param("filterValue") String filterValue);
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);