Sử dụng OneToMany Relationship trong spring jpa

Giới thiệu nội dung bài viết

Chào các em ,chủ đề hôm nay chúng ta sẽ nói về các annotation @OneToMany@ManyToOne trong Spring JPA .


1. One To Many annotation

Anh lấy ví dụ như mình làm ứng dụng về bán hàng. Mình có chức năng thêm sản phẩm (Item) vào giỏ hàng (cart) . Trong giỏ hàng (cart) sẽ chứa nhiều sản phẩm (Items). Như vậy quan hệ giữa giỏ hàng và sản phẩm là One To Many nghĩa là 1 giỏ hàng chứa nhiều sản phẩm.

Nếu ta thiết kế database thì ta có 2 bảng là cart và item như sau .

1
2
3
4
5
6
7
8
9
10
11
12
CREATE TABLE `Cart` (
  `cart_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`cart_id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

CREATE TABLE `Items` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `cart_id` int(11) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  KEY `cart_id` (`cart_id`),
  CONSTRAINT `items_ibfk_1` FOREIGN KEY (`cart_id`) REFERENCES `Cart` (`cart_id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;

Như vậy mối quan hệ trong database giữa Cart và Item là một nhiều. Column cart_id là khóa chính trong bảng Cart và là khóa phụ trong bảng Items.

Trong Java mình thể hiện mối quan hệ 1 - nhiều qua annotation @OneToMany. Ví dụ như ta khai báo lớp Cart có quan hệ một nhiều với lớp Item như sau.

1
2
3
4
5
6
public class Cart {

    @OneToMany(mappedBy="cart")
    private Set<Items> items;

}

Chúng ta sử dụng annotation @OneToMany để nói lên mối liên hệ một nhiều. Như ví dụ trên ta có thể thấy 1 giỏ hàng (Cart) có nhiều sản phẩm Items. Ở trên chúng ta sử dụng collection là Set vì chúng ta muốn tập hợp sản phẩm không được trùng lặp nhau. Các em có thể sử dụng các tập hợp khác như List, Map cũng được. Tuỳ theo mục đích sử dụng mà mình chọn tập hợp cho đúng


**2. Triển khai trong Java code

Bây giờ anh sẽ hướng dẫn các bạn xây dựng ứng dụng shopping cart. Sử dụng @OneToMany và @ManyToOne để thiết lập mối quan hệ giữa Cart (giỏ hàng) và Item (sản phẩm).


Bước 1. Tạo các tables : Cart và Item

1
2
3
4
5
6
7
8
9
10
11
12
CREATE TABLE `Cart` (
  `cart_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`cart_id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

CREATE TABLE `Items` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `cart_id` int(11) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  KEY `cart_id` (`cart_id`),
  CONSTRAINT `items_ibfk_1` FOREIGN KEY (`cart_id`) REFERENCES `Cart` (`cart_id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;


Bước 2. Thêm dependency trong maven

1
2
3
4
5
6
7
8
9
10
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

         <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
         </dependency>


Bước 3. Tạo Entity Cart

1
2
3
4
5
6
7
8
9
10
11
12
13
@Entity
@Table(name="CART") // tên này trùng với tên Table trong database .
public class Cart {

    //...

    @OneToMany(mappedBy="cart") // chú ý biến cart này được khai báo trong Class Item bên dưới. Chúng phải giống y chang nhau cái tên
    private Set<Items> items;

    public Set<Items> getItems () {
      return items ;
    }
}

Chúng ta chú ý, theo yêu cầu thì một giỏ hàng (Cart) sẽ chứa nhiều sản phẩm giống như trong database mô tả. Để làm được việc đó Ta sử dụng @OneToMany trong Class Cart, điều đó có nghĩa 1 giỏ hàng sẽ có nhiều sản phẩm (Items).

Tiếp đến ta sẽ thấy từ mappedBy = “cart”. MappedBy dùng để định nghĩa Class Cart và Class Item sẽ liên kết với nhau thông qua tên “cart”. Và bắt buộc tên “cart” phải được định nghĩa trong Class Item. MappedBy giống như là 1 cầu nối để ta có thể từ Class Cart mình gọi hàm getItems mình sẽ nhận được một danh sách Items


Bước 4. Tạo Entity Items

1
2
3
4
5
6
7
8
9
10
11
12
13
@Entity
@Table(name="ITEMS")
public class Items {

    //...
    @ManyToOne
    @JoinColumn(name="cart_id", nullable=false) //cart_id chính là trường khoá phụ trong table Item liên kết với khóa chính trong table Cart
    private Cart cart;

    public Items() {}

    // getters and setters
}

Chúng ta thấy trong lớp Cart chúng ta định nghĩa @OneToManymappedBy với giá trị “cart” để tạo liên kết giữa lớp Cart và Item . Để liên kết đó hoạt động thì ta cũng phải cấu hình biến “cart” trong Class Item.

Đầu tiên chúng ta sử dụng @ManyToOne và @JoinColumn để định nghĩa cho biến cart để tạo sự liên kết ngược lại giữa Class Items và Cart.Trong @JoinColumn ta định nghĩa name = “cart_id” . Cái ‘cart_id ‘ chính là column khóa phụ trong table Items mà ta định nghĩa trong database . nullable = false là ta ràng buộc dữ liệu không được phép null


Bước 5. Test ứng dụng

Chúng ta sẽ lưu giỏ hàng và các sản phẩm xuống database theo cách sau. Khi dữ liệu được lưu thì nó sẽ được lưu xuống cả 2 tables cùng một lúc.

1
2
3
4
5
6
7
8
9
 Items item1 = new Items ("Item 1");
 Items item2 = new Items ("Item 2");
 Set<Items> items = new HashSet<Items>();
 items.add(item1);
 items.add(item2);

 Cart cart = new Cart();
 cart.setItems(items);
 cart.save(); // như vậy ta sẽ lưu dữ liệu xuống 2 bảng Cart và Items


3. Kết luận

Như vậy chúng ta sử dụng annotation @OneToMany và @ManyToOne để thực hiện việc liên kết giữa hai entity với nhau. Trong lập trình sẽ có những lúc khi ta có thể query từ Cart lấy ra tất cả các dòng dữ liệu Items trong Cart đó hoặc sẽ có những trường hợp ngược lại là từ những Items trong Cart đó ta có thể lấy được Cart đó là gì thông qua các Item. Đó chính là Bidirectional chúng ta có thể query Cart lấy Item hoặc query ngược từ Item ra Cart. Để làm được việc này thì ta phải sử dụng @JoinColumn và MappedBy để thực hiện Bidirectional

4. Video Demo

5. Source code

Sourcecode


Mọi người hãy Subscribe kênh youtube dưới đây nhé để cập nhật các video mới nhất về kỹ thuật và kỹ năng mềm

Các khoá học lập trình MIỄN PHÍ tại đây


Comments