[series Spring Boot] 16. Spring Data Jpa 4

Trong bài viết này, chúng ta sẽ cùng tìm hiểu về relationship trong Spring Data Jpa.

- Spring Data Jpa hỗ trợ chúng ta khai báo quan hệ khóa chính/khóa ngoại cho các ORM/Entity.
- Các annotation thường gặp
  • @OneToOne: Khai báo quan hệ 1-1
  • @OneToMany: Khai báo quan hệ 1-n
  • @ManyToOne: Khai báo quan hệ n-1
  • @ManyToMany: Khai báo quan hệ n-n
- Trong bài này, mình sẽ hướng dẫn các bạn sử dụng annotation @OneToMany
- Giả sử bạn xây dụng 1 trang web bán hàng, bạn sẽ làm việc với 2 table: BILL và BILL_DETAIL
- Cấu trúc các table như sau:
  • BILL(ID, BILL_CODE, CUSTOMER_NAME). Cột ID là khóa chính.
  • BILL_DETAIL(ID, BILL_ID, PRODUCT, QUANTITY). Cột ID là khóa chính, BILL_ID là khóa ngoại tham chiếu đến cột ID của bảng BILL.
- Giả sử chúng ta không tạo quan hệ cho 2 ORM của 2 table trên thì code sẽ có dạng

Bill.java
Java:
package vn.congdongjava.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "BILL")
public class Bill {

    @Id
    @Column(name = "ID")
    private Long id;

    @Column(name = "BILL_CODE")
    private String billCode;

    @Column(name = "CUSTOMER_NAME")
    private String customerName;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getBillCode() {
        return billCode;
    }

    public void setBillCode(String billCode) {
        this.billCode = billCode;
    }

    public String getCustomerName() {
        return customerName;
    }

    public void setCustomerName(String customerName) {
        this.customerName = customerName;
    }
}
BillDetail.java
Java:
package vn.congdongjava.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "BILL_DETAIL")
public class BillDetail {

    @Id
    @Column(name = "ID")
    private Long id;

    @Column(name = "BILL_ID")
    private Long billId;

    @Column(name = "PRODUCT")
    private String product;

    @Column(name = "QUANTITY")
    private Long quantity;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Long getBillId() {
        return billId;
    }

    public void setBillId(Long billId) {
        this.billId = billId;
    }

    public String getProduct() {
        return product;
    }

    public void setProduct(String product) {
        this.product = product;
    }

    public Long getQuantity() {
        return quantity;
    }

    public void setQuantity(Long quantity) {
        this.quantity = quantity;
    }
}
BillRepository.java
Java:
package vn.congdongjava.dao;

import org.springframework.data.jpa.repository.JpaRepository;
import vn.vccb.entity.Bill;

public interface BillRepository extends JpaRepository<Bill, Long> {
}
BillDetailRepository.java
Java:
package vn.vccb.dao;

import org.springframework.data.jpa.repository.JpaRepository;
import vn.vccb.entity.BillDetail;

import java.util.List;

public interface BillDetailRepository extends JpaRepository<BillDetail, Long> {

    List<BillDetail> getByBillId(Long billId);
}
HomeController.java
Java:
package vn.congdongjava.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import vn.vccb.dao.BillDetailRepository;
import vn.vccb.dao.BillRepository;
import vn.vccb.entity.Bill;
import vn.vccb.entity.BillDetail;

import java.util.List;

@Controller
public class HomeController {

    @Autowired
    private BillRepository billRepository;

    @Autowired
    private BillDetailRepository billDetailRepository;

    @GetMapping("{id}")
    public String showBill(@PathVariable Long id, Model model) {
        Bill bill;
        List<BillDetail> lstBillDetail;

        bill = billRepository.getOne(id);
        lstBillDetail = billDetailRepository.getByBillId(id);

        model.addAttribute("bill", bill);
        model.addAttribute("lstBillDetail", lstBillDetail);

        return "index";
    }
}
- Nhìn vào cách lấy thông tin hóa đơn tại HomeController, ta thấy các phần của dữ liệu hóa đơn được lấy ra một cách rời rạt, khó có thể thấy được mối quan hệ giữa bảng BILL và BILL_DETAIL.
- Sử dụng annotation @OneToMany giúp chúng ta dễ dàng thấy được mối quan hệ giữa các bảng mà không cần phải dùng đến database diagram. Quan trọng hơn là Spring Data Jpa sẽ tự động get các dữ liệu có quan hệ khóa ngoại của bảng có dòng dữ liệu được get ra.
- Thực hiện thay đổi source code như sau

Bill.java
Java:
package vn.congdongjava.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import java.util.List;

@Entity
@Table(name = "BILL")
public class Bill {

    @Id
    @Column(name = "ID")
    private Long id;

    @Column(name = "BILL_CODE")
    private String billCode;

    @Column(name = "CUSTOMER_NAME")
    private String customerName;

    @OneToMany
    @JoinColumn(name = "BILL_ID")
    private List<BillDetail> listDetail;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getCustomerName() {
        return customerName;
    }

    public void setCustomerName(String customerName) {
        this.customerName = customerName;
    }

    public List<BillDetail> getListDetail() {
        return listDetail;
    }

    public void setListDetail(List<BillDetail> listDetail) {
        this.listDetail = listDetail;
    }
}
BillDetail.java
Java:
package vn.congdongjava.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "BILL_DETAIL")
public class BillDetail {

    @Id
    @Column(name = "ID")
    private Long id;

    @Column(name = "PRODUCT")
    private String product;

    @Column(name = "QUANTITY")
    private Long quantity;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getProduct() {
        return product;
    }

    public void setProduct(String product) {
        this.product = product;
    }

    public Long getQuantity() {
        return quantity;
    }

    public void setQuantity(Long quantity) {
        this.quantity = quantity;
    }
}
HomeController.java
Java:
package vn.congdongjava.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import vn.vccb.dao.BillDetailRepository;
import vn.vccb.dao.BillRepository;
import vn.vccb.entity.Bill;
import vn.vccb.entity.BillDetail;

import java.util.List;

@Controller
public class HomeController {

    @Autowired
    private BillRepository billRepository;

    @Autowired
    private BillDetailRepository billDetailRepository;

    @GetMapping("{id}")
    public String showBill(@PathVariable Long id, Model model) {
        Bill bill;
        List<BillDetail> lstBillDetail;

        bill = billRepository.getOne(id);
        lstBillDetail = bill.getListDetail();

        model.addAttribute("bill", bill);
        model.addAttribute("lstBillDetail", lstBillDetail);

        return "index";
    }
}
- Có thể thấy, thay vì khai báo trường billId trong entity BillDetail thì ta khai báo trường listDetail có kiểu List<BillDetail> ngay trong entity Bill
- Tại HomeController, thay vì phải dòng BillDetailRepository để get các dòng của bảng BILL_DETAIL thì Spring Data Jpa đã get luôn cho chúng ta, chỉ còn dùng method getListDetail để truy cập vào.


Cám ơn các bạn đã theo dõi. Hẹn gặp lại trong bài viết tiếp theo :)
 
Sửa lần cuối:

Bình luận