Hướng dẫn annotation @Query / NativeQuery trong Spring data

Hướng dẫn annotation @Query / NativeQuery trong Spring data

Spring Data annotation @Query

Với annotation @Query ta có thể khai báo câu query cho các method trong repository.

Việc khai báo câu query với @Query giúp ta tối ưu câu sql, và xử lý trong những trường hợp mà các method do Spring Data không thể đáp ứng:

  • Việc sử dụng các method có sẵn khi extends interface JPARepositoryCrudRepository  không đáp ứng được yêu cầu.
  • Việc đặt tên method theo chuẩn Query Creation quá dài hoặc tối nghĩa. (Ví dụ bạn muốn truy vấn theo 5 điều kiện thì tên method của bạn sẽ gồm 5 điều kiện đó => quá dài)

Sử dụng @Query

Để sử dụng annotation @Query, ta sẽ khai báo nó trước các method của interface extends từ JPARepositoryCrudRepository , và truyền câu hsql vào bên trong

Ví dụ:

  • @Repository
  • public interface CustomerRepository extends JpaRepository<Customer, Integer> {
  • @Query("SELECT e FROM Customer e ORDER BY e.name DESC")
  • List<Customer> findAllOrderByNameDesc();
  • }
@Repository
public interface CustomerRepository extends JpaRepository<Customer, Integer> {

  @Query("SELECT e FROM Customer e ORDER BY e.name DESC")
  List<Customer> findAllOrderByNameDesc();
}

Với trường hợp câu sql có tham số từ bên ngoài ta có 2 cách để truyền vào:

Cách 1: truyền theo thứ tự:

  • @Repository
  • public interface CustomerRepository extends JpaRepository<Customer, Integer> {
  • @Query("SELECT e FROM Customer e WHERE e.name = ?1 AND e.address = ?2")
  • List<Customer> findByNameAndAddress(String name, String address);
  • }
@Repository
public interface CustomerRepository extends JpaRepository<Customer, Integer> {

  @Query("SELECT e FROM Customer e WHERE e.name = ?1 AND e.address = ?2")
  List<Customer> findByNameAndAddress(String name, String address);

}

Với cách này thứ tự các tham số của method phải giống với thứ tự các tham số truyền vào câu query

Cách 2: sử dụng annotation @Param

  • @Repository
  • public interface CustomerRepository extends JpaRepository<Customer, Integer> {
  • @Query("SELECT e FROM Customer e WHERE e.name = :name AND e.address = :address")
  • List<Customer> findByNameAndAddress(@Param("name") String name, @Param("address") String address);
  • }
@Repository
public interface CustomerRepository extends JpaRepository<Customer, Integer> {

  @Query("SELECT e FROM Customer e WHERE e.name = :name AND e.address = :address")
  List<Customer> findByNameAndAddress(@Param("name") String name, @Param("address") String address);

}

Bản thân mình thấy cách này rõ ràng hơn, câu query vừa dễ đọc lại không lo nhầm thứ tự các tham số.

Kết quả trả về của method sử dụng @Query

Kết quả trả về của method sử dụng @Query có thể là:

Một List:

  • @Repository
  • public interface CustomerRepository extends JpaRepository<Customer, Integer> {
  • @Query("SELECT e FROM Customer e WHERE e.name = :name")
  • List<Customer> findByName(@Param("name") String name);
  • }
@Repository
public interface CustomerRepository extends JpaRepository<Customer, Integer> {
  @Query("SELECT e FROM Customer e WHERE e.name = :name")
  List<Customer> findByName(@Param("name") String name);
}

Một Stream:

  • @Repository
  • public interface CustomerRepository extends JpaRepository<Customer, Integer> {
  • @Query("SELECT e FROM Customer e WHERE e.name = :name")
  • Stream<Customer> findByName(@Param("name") String name);
  • }
@Repository
public interface CustomerRepository extends JpaRepository<Customer, Integer> {
  @Query("SELECT e FROM Customer e WHERE e.name = :name")
  Stream<Customer> findByName(@Param("name") String name);
}

Ta dùng stream cho những trường hợp kết quả của câu query có quá nhiều bản ghi, thay vì phải tạo rất nhiều đối tượng để lưu các bản ghi đó ta sẽ tạo ra 1 stream, và nó chỉ thực sự tạo ra các đối tượng khi bạn sử dụng đến phần tử bên trong stream.

Một Page:

  • @Repository
  • public interface CustomerRepository extends JpaRepository<Customer, Integer> {
  • @Query("SELECT e FROM Customer e WHERE e.name = :name")
  • Page<Customer> findByName(@Param("name") String name, Pageable pageable);
  • }
@Repository
public interface CustomerRepository extends JpaRepository<Customer, Integer> {
  @Query("SELECT e FROM Customer e WHERE e.name = :name")
  Page<Customer> findByName(@Param("name") String name, Pageable pageable);
}

(Việc trả về Page áp dụng cho trường hợp muốn phân trang, mình sẽ nói rõ hơn ở bài sau)

Một đối tượng:

  • @Repository
  • public interface CustomerRepository extends JpaRepository<Customer, Integer> {
  • @Query("SELECT e FROM Customer e WHERE e.name = :name")
  • Customer findByName(@Param("name") String name);
  • }
@Repository
public interface CustomerRepository extends JpaRepository<Customer, Integer> {
  @Query("SELECT e FROM Customer e WHERE e.name = :name")
  Customer findByName(@Param("name") String name);
}

Ta chỉ sử dụng khi chắc chắn kết quả của câu query sẽ trả về 1 đối tượng, nếu câu query trả về nhiều hơn 1 đối tượng thì sẽ xảy ra lỗi.

Sử dụng NativeQuery

Để sử dụng native query ta sử dụng thuộc tính nativeQuery = true bên trong annotation @Query

Ví dụ:

  • @Repository
  • public interface CustomerRepository extends JpaRepository<Customer, Integer> {
  • @Query(value = "SELECT e.* FROM customer e ORDER BY e.name DESC", nativeQuery = true)
  • List<Customer> findAllOrderByNameDesc();
  • }
@Repository
public interface CustomerRepository extends JpaRepository<Customer, Integer> {
  @Query(value = "SELECT e.* FROM customer e ORDER BY e.name DESC", nativeQuery = true)
  List<Customer> findAllOrderByNameDesc();
}

 

Okay, Done!

(Xem thêm code ví dụ Spring Boot Data JPA annotation @Query)

 

References:

https://docs.spring.io/spring-data/…/-query

stackjava.com