Database phần 2 - Tùy biến, Query

1. Tùy cột trong bảng dữ liệu

Giả sử ta có model như sau

@Entity
@Data
public class Author {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;

    private String name;
    private String email;
    private String website;
    private String favoriteQuote;
}

Thì tương ứng, ta có được bảng dữ liệu như sau MySQL

Ở đây

Ngoài ra, còn có nhiều annotitaion khác có thể thay đổi thuộc tính của các cột, bao gồm

Validation dữ liệu

Bổ sung thông tin cột

Khai báo các quan hệ (Sẽ nghiên cứu kỹ ở phần sau)

2. Tùy biến các câu lệnh query

Ở phần trước, ta đã biết cách khai báo một repository như sau

public interface AuthorRepository extends JpaRepository<Author, Integer> {
}

Những hàm mà một authorRepository cung cấp:

Ngoài ra, ta có thể khai báo thêm các method với tên theo quy tắc và danh sách tham số phù hợp, framework sẽ đi implement giùm. Ví dụ

public interface AuthorRepository extends JpaRepository<Author, Integer> {
    List<Author> findByNameContaining(String name);
}

Tên hàm findByNameContaining với findBy là tìm author theo điều kiện và NameContaining tức là tên chứa chuỗi name ở trong param.

Kết quả MySQL

Query bằng tên hàm

Khi đặt tên một hàm trong repository bắt đầu với find, query, read, get, count và tiếp theo bởi by và danh sách từ khóa điều kiện

Từ khóa Ý nghĩa Minh họa bằng sql
And Kết hợp AND hai điều kiện …where lastname = ?1 and firstname = ?2
Or Kết hợp OR hai điều kiện …where lastname = ?1 or firstname = ?2
Is, Equals Kiểm tra dữ liệu phải bằng …where name = ?1
Between Kiểm tra dữ liệu trong phạm vi …where startDate between ?1 and ?
LessThan Dữ liệu nhỏ hơn …where year < ?1
LessThanEqual Dữ liệu nhỏ hơn hoặc bằng …where year <= ?1
GreaterThan Dữ liệu lớn hơn …where year > ?1
GreaterThanEqual Dữ liệu lớn hơn hoặc bằng …where year >= ?1
After Dữ liệu ngày tháng phải sau …where startDate > ?1
Before Dữ liệu ngày tháng phải trước …where startDate < ?1
IsNull Dữ liệu là null …where name is null
IsNotNull, NotNull Dữ liệu khác null …where name not null
Like Dữ liệu string hợp pattern …where name like ?1
NotLike Dữ liệu string không hợp pattern …where name not like ?1
StartingWith Dữ liệu string bắt đầu với …where name like ?1
EndingWith Dữ liệu string kết thúc với …where name like ?1
Containing Dữ liệu string chứa …where name like ?1
OrderBy Sắp xếp kết quả trả về theo …where year = ?1 order by name desc
Not Phủ định điều kiện …where name <> ?1
In Dữ liệu thuộc danh sách …where year in ?1
NotIn Dữ liệu không thuộc danh sách …where year not in ?1
True Dữ liệu là true …where valid = true
False Dữ liệu là false …where valid = false
IgnoreCase Không kiểm tra chữ hoa thường …where UPPER(name) = UPPER(?1)

Ví dụ

import com.voquanghoa.bookstore.models.Author;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

public interface AuthorRepository extends JpaRepository<Author, Integer> {
    List<Author> findByNameContainingIgnoreCase(String name);
    List<Author> findByNameOrEmail(String name, String email);
    List<Author> findByNameContainingOrEmailContaining(String name, String email);
}

Bằng cách sử dụng tên hàm, thư viện sẽ generate câu lệnh sql phù hợp.

Sử dụng Query

Ta chỉ định sql để thực hiện việc query thay vì để thư viện generate dựa theo tên hàm như trên.

import com.voquanghoa.bookstore.models.Author;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

public interface AuthorRepository extends JpaRepository<Author, Integer> {
    @Query("select u from Author u where email = ?1")
    List<Author> findByEmailAddress(String emailAddress);
}

Ở đây ?1 là giá trị sẽ được thay thế bởi tham số emailAddress, hoặc một cách tường minh hơn, giá trị tham số hàm có thể được điền bằng cách dùng tên

public interface AuthorRepository extends JpaRepository<Author, Integer> {
    @Query("select u from Author u where email = :emailAddress")
    List<Author> findByEmailAddress(String emailAddress);
}

Cập nhật dữ liệu

Ta có thể cập nhật dữ liệu với thao tác UPDATE/DELETE bằng query với Annotation @Modifing như sau:

import com.voquanghoa.bookstore.models.Author;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.transaction.annotation.Transactional;

public interface AuthorRepository extends JpaRepository<Author, Integer> {

    @Transactional
    @Modifying
    @Query("delete Author where email = :emailAddress")
    void deleteByEmail(String emailAddress);

    @Transactional
    @Modifying
    @Query(value = "update Author set email = :newEmail  where id = :id")
    void updateEmailById(int id, String newEmail);
}

@Transactional đảm bảo việc cập nhật (sửa/xóa) thành công mà không bị một thao tác khác xen ngang. Đối với một số trường hợp, đây là annotation phải có để cập nhật dữ liệu.

Tài liệu tham khảo thêm

https://docs.spring.io/spring-data/jpa/docs/current/reference/html/ https://o7planning.org/vi/11661/huong-dan-spring-boot-jpa-va-spring-transaction https://www.journaldev.com/17034/spring-data-jpa https://www.petrikainulainen.net/spring-data-jpa-tutorial/

Bài tập

  1. Thêm thuộc tính price và thêm vào Repository phương thức tìm kiếm sách có giá trong phạm vi min đến max
  2. Thay đổi router /find để nhận vào một query q có thể tìm kiếm book có name query q
  3. Thay đổi router GET “” để nhận vào các optional parametter String q, String order, String orderType=”ASC”, thay đổi response dựa theo params.

Xem

Trang chủ