Spring JPA Method + @Query
Query Creation
Trong Spring JPA, có một cơ chế giúp chúng ta tạo ra các câu Query mà không cần viết thêm code. Cơ chế này xây dựng Query từ tên của method. Ví dụ: Chúng ta có đối tượng User
.
User.java
@Entity
@Table(name = "user")
@Data
public class User implements Serializable {
private static final long serialVersionUID = -297553281792804396L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// Mapping thông tin biến với tên cột trong Database
@Column(name = "hp")
private int hp;
@Column(name = "stamina")
private int stamina;
// Nếu không đánh dấu @Column thì sẽ mapping tự động theo tên biến
private int atk;
private int def;
private int agi;
}
Khi chúng ta đặt tên method là: findByAtk(int atk)
. Thì Spring JPA sẽ tự định nghĩa câu Query cho method này, bằng cách xử lý tên method. Vậy là chúng ta đã có thể truy vấn dữ liệu mà chỉ mất thêm 1 dòng code.
Quy tắc đặt tên method trong Spring JPA
Trong Spring JPA, cơ chế xây dựng truy vấn thông qua tên của method được quy định bởi các tiền tố sau:
find…By
, read…By
, query…By
, count…By
, và get…By
.
phần còn lại sẽ được parse theo tên của thuộc tính (viết hoa chữ cái đầu). Nếu chúng ta có nhiều điều kiện, thì các thuộc tính có thể kết hợp với nhau bằng chữ And
hoặc Or
. Bạn có thể đọc thêm trong Docs của Spring: Query Creation
Ví dụ:
interface PersonRepository extends JpaRepository<User, Long> {
// Dễ
// version rút gọn
Person findByLastname(String lastname);
// verson đầy đủ
Person findPersonByLastname(String lastname);
Person findAllByLastname(String lastname);
// Trung bình
List<Person> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname);
// findDistinct là tìm kiếm và loại bỏ đi các đối tượng trùng nhau
List<Person> findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname);
List<Person> findPeopleDistinctByLastnameOrFirstname(String lastname, String firstname);
// IgnoreCase là tìm kiếm không phân biệt hoa thường, ví dụ ở đây tìm kiếm lastname
// lastname sẽ không phân biệt hoa thường
List<Person> findByLastnameIgnoreCase(String lastname);
// AllIgnoreCase là không phân biệt hoa thường cho tất cả thuộc tính
List<Person> findByLastnameAndFirstnameAllIgnoreCase(String lastname, String firstname);
// OrderBy là cách sắp xếp thứ tự trả về
// Sắp xếp theo Firstname ASC
List<Person> findByLastnameOrderByFirstnameAsc(String lastname);
// Sắp xếp theo Firstname Desc
List<Person> findByLastnameOrderByFirstnameDesc(String lastname);
}
Các thuộc tính trong tên method phải thuộc về Class đó, nếu không sẽ gây ra lỗi. Tuy nhiên, trong một số trường hợp bạn có thể query bằng thuộc tính con. Ví dụ: Đói tượng Person
có thuộc tính là Address
và trong Address
lại có ZipCode
// person.address.zipCode
List<Person> findByAddressZipCode(ZipCode zipCode);
@Query
Với cách sử dụng @Query
, bạn sẽ có thể sử dụng câu truy vấn JPQL (Hibernate) hoặc SQL thuần (raw SQL). Ví dụ:
public interface UserRepository extends JpaRepository<User, Long> {
// Khi được gắn @Query, thì tên của method không còn tác dụng nữa
// Đây là JPQL
@Query("select u from User u where u.emailAddress = ?1")
User myCustomQuery(String emailAddress);
// Đây là Native SQL
@Query(value = "select * from User u where u.email_address = ?1", nativeQuery = true)
User myCustomQuery2(String emailAddress);
}
Cách truyền tham số là gọi theo thứ tự các tham số của method bên dưới ?1
, ?2
. Nếu bạn không thích sử dụng ?{number}
thì có thể đặt tên cho tham số.
public interface UserRepository extends JpaRepository<User, Long> {
// JPQL
@Query("SELECT u FROM User u WHERE u.status = :status and u.name = :name")
User findUserByNamedParams(@Param("status") Integer status, @Param("name") String name);
// Native SQL
@Query(value = "SELECT * FROM Users u WHERE u.status = :status and u.name = :name", nativeQuery = true)
User findUserByNamedParamsNative(@Param("status") Integer status, @Param("name") String name);
}