Các cách mapping entity với quan hệ kế thừa
- Joined Table: mỗi class là một bảng, yêu cầu join bảng
- MappedSuperClass: class cha không phải là entity
- Single Table: class cha là một entity
- Table-Per-Class: mỗi class là một bảng riêng với tất cả thuộc tính
Source code tham khảo: https://github.com/TechMaster/SpringBoot28Days/tree/27a0de8d52f72c30632a1ec9820d1e912305a554/15-CustomRepository/relation
2. Phần này chúng ta sẽ đi tìm hiểu từng cách
2.1. JoinTable
Ta có 1 entity cha và 2 entity con như sau:
- Abstract Course Entity: entity cha
- OnlineCourse, OfffineCourse : 2 entity con
Course Entity
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@Data
@NoArgsConstructor
public abstract class Course {
@Id @GeneratedValue(strategy = GenerationType.AUTO)
protected Long id;
//...
}
- Ta sử dụng annotation @Inheritance(strategy = InheritanceType.JOINED) ở entity cha
OnlineCourse Entity
@Entity(name = "onlinecourse")
@Data
public class OnlineCourse extends Course {
private int numberOfVideos;
}
OfflineCourse Entity
@Entity(name = "offlinecourse")
@Data
@NoArgsConstructor
public class OfflineCourse extends Course {
private int numberOfLessons;
private float totalHours;
}
Chú thích
Với join table, ta thu được mô hình quan hệ như sau, cơ sở dữ liệu sẽ sinh ra một bảng đại diện cho entity cha:
- Cách này sẽ làm giảm performent vì cần join bảng
- Khóa chính ở entity cha sẽ là cột dùng cho việc join bảng
Ta thực hiện thi ứng dụng như sau
@Transactional
public void generateCourse() {
Course javaOffline = new OfflineCourse("Java offline course", 28, 80);
OnlineCourse javaOnline = new OnlineCourse();
javaOnline.setTitle("Java offline Course");
em.persist(javaOffline);
em.persist(javaOnline);
}
Sau khi chạy ứng dụng ta thu được Log Query như sau:
insert into course (title, id) values (?, ?)
insert into offlinecourse (number_of_lessons, total_hours, id) values (?, ?, ?)
insert into course (title, id) values (?, ?)
insert into onlinecourse (number_of_videos, id) values (?, ?)
2.2. MappedSuperClass
Ta có 1 class cha và 2 entity con như sau:
- Class BaseProduct: class cha, không phải entity.
- Shirt, Shoe: 2 entity con.
BaseProduct
@MappedSuperclass
public class BaseProduct {
@Id @GeneratedValue(strategy = GenerationType.AUTO)
private long id;
//...
}
- Với cách này ta sử dụng annotation @MappedSuperclass ở class cha
Shirt
@Entity(name = "shirt")
@Table(name = "shirt")
public class Shirt extends BaseProduct{
//...
}
Shoe
@Entity(name = "shoe")
@Table(name = "shoe")
public class Shoe extends BaseProduct{
//...
}
Chú thích
Với mapping supper class, ta thu được mô hình quan hệ như sau :
- Cơ sở dữ liệu sẽ chỉ có các bảng là các entity con, các thuộc tính của class cha sẽ nằm trong các bảng của entity con
Ta thực hiện thi ứng dụng như sau
@Transactional
public void generateProduct() {
Shoe nikeAirZoom = new Shoe("Nike Air Zoom Pegasus 38", "Nike", ShoeSize.EU43);
Shirt hermesSweater = new Shirt("Hermes Sweater", "Hermes", ClothesSize.L, Color.WHITE);
em.persist(nikeAirZoom);
em.persist(hermesSweater);
}
Sau khi chạy ứng dụng ta thu được Log Query như sau:
insert into shoe (manufacturer, name, size, id) values (?, ?, ?, ?)
insert into shirt (manufacturer, name, color, size, id) values (?, ?, ?, ?, ?)
2.3. Single Table
Ta có entity cha và 2 entity con như sau:
- Entity Electronics: entity cha
- Fridge, Laptop: 2 entity con
Electronics
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class Electronics {
@Id @GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private String manufacturer;
private String model;
//...
}
- Ta sử dụng annotation @Inheritance(strategy = InheritanceType.SINGLE_TABLE) ở entity cha
Fridge
@Entity(name="fridge")
public class Fridge extends Electronics {
//...
}
Laptop
@Entity(name="laptop")
public class Laptop extends Electronics {
//...
}
Chú thích
Với single table mapping, ta thu được mô hình quan hệ như sau:
- Cơ sở dữ liệu sẽ sinh ra một bảng duy nhất đại diện cho tất cả các entity con và cha
- Với cách này việc query sẽ rất nhanh
- Nhược điểm, mỗi entity chỉ sử dụng một trong số tất cả các trường của bảng, không thể đặt constraints lên một cột nào được vì có thể ảnh hưởng đến entity khác.
- Nhược điểm, single table sẽ tạo ra cột dư thừa trong các row
Ta thực hiện thi ứng dụng như sau
@Transactional
public void generateEletronicsProducts() {
Laptop dellInspiron = new Laptop("Inspiron M6800", "DELL", "M6800",
CPUType.INTEL_CORE_I7, 16, 17.3F);
Fridge samsung230L = new Fridge("Samsung 230 Inverter", "Samsung", "230L",
230, Voltage.AC220);
em.persist(dellInspiron);
em.persist(samsung230L);
}
Sau khi chạy ứng dụng ta thu được Log Query như sau:
insert into electronics (manufacturer, model, name, cpu_type, ram_size, screen_size, dtype, id) values (?, ?, ?, ?, ?, ?, 'Laptop', ?)
insert into electronics (manufacturer, model, name, voltage, volume, dtype, id) values (?, ?, ?, ?, ?, 'Fridge', ?)
2.4. Table Per Class
Ta có 1 entity cha và 3 enity con như sau:
- Animal: entity cha
- Fish, Mammal, Reptile: 3 entity con
Animal
@Entity(name = "animal")
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Animal {
@Id @GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
//...
}
- Ta sử dụng annotation @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) ở entity cha
Fish
@Entity(name = "Fish")
public class Fish extends Animal{
//...
}
Mammal
@Entity(name = "Mammal")
public class Mammal extends Animal {
//...
}
Reptile
@Entity(name = "reptile")
public class Reptile extends Animal {
//...
}
Chú thích
Với table per class, ta thu được mô hình quan hệ như sau:
- Cách này giống với mapped super class ở điểm database sẽ không tạo thêm bảng cho entity cha, nhưng khác nhau ở chỗ với table per class thì class cha là entity.
- Mỗi entity sẽ ở một bảng riêng và bao gồm các thuộc tính của class cha
Ta thực hiện thi ứng dụng như sau
@Transactional
public void generateAnimals() {
Fish caTram = new Fish("Trắm", FishType.FRESH_WATER);
Mammal tiger = new Mammal("Hổ Bengal", EatType.CARNIVO);
Reptile cobra = new Reptile("Rắn hổ mang", ReptileType.SNAKE);
em.persist(caTram);
em.persist(tiger);
em.persist(cobra);
}
Sau khi chạy ứng dụng ta thu được Log Query như sau:
insert into fish (name, fish_type, id) values (?, ?, ?)
insert into mammal (name, eat_type, id) values (?, ?, ?)
insert into reptile (name, type, id) values (?, ?, ?)
Bình luận