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 (?, ?, ?)