JPA 实体继承共用一个表

在用JPA的时候,如果每个实体都有一些共通的属性,例如创建时间,最后修改时间,那可以把这些属性放到一个公共实体里,用 @MappedSuperclass 标记,然后其它实体继承这个类即可。这个是简单的方式,下面说一下真正的实体继承。

先说一个场景,开发一个产品实体,过几天产品狗告诉你,有个特殊的产品钢笔,这里有2个特殊的属性,品牌和钢笔的粗细,在你还没发火之前,又告诉你还有另外一个特殊的产品订书器,它有长和宽。

按照面向对象的思维,你需要创建另外2个实体然后继承之前的实体来实现。代码如下:

package com.school1024.spring.boot.data.jpa.model.inheritance;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorType;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;

@Entity(name = "product")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.STRING)
@DiscriminatorValue("product")
public class ProductModel implements Serializable {

private static final long serialVersionUID = 6106176643457208464L;

// 主键
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;

// 编码
@Column(length = 64, unique = true)
private String code;

// 名字
@Column(length = 64, unique = true)
private String name;

// 描述
@Column(length = 512)
private String description;

public ProductModel() {
super();
}

public ProductModel(String code, String name, String description) {
super();
this.code = code;
this.name = name;
this.description = description;
}

public Integer getId() {
return id;
}

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

public String getCode() {
return code;
}

public void setCode(String code) {
this.code = code;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}

@Override
public String toString() {
return "ProductModel [id=" + id + ", code=" + code + ", name=" + name + ", description=" + description + "]";
}

}

Pen

package com.school1024.spring.boot.data.jpa.model.inheritance;

import java.math.BigDecimal;

import javax.persistence.Column;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;

@Entity(name = "pen")
@DiscriminatorValue("pen")
public class PenModel extends ProductModel {

private static final long serialVersionUID = 8894852982881457722L;

// 尺码,0.5mm 0.8mm
@Column(precision = 4, scale = 2)
private BigDecimal size;

// 品牌
private String brand;

public PenModel() {
super();
}

public PenModel(String code, String name, String description, BigDecimal size, String brand) {
super(code, name, description);
this.size = size;
this.brand = brand;
}

public BigDecimal getSize() {
return size;
}

public void setSize(BigDecimal size) {
this.size = size;
}

public String getBrand() {
return brand;
}

public void setBrand(String brand) {
this.brand = brand;
}

@Override
public String toString() {
return "PenModel [size=" + size + ", brand=" + brand + ", toString()=" + super.toString() + "]";
}

}

Stapler

package com.school1024.spring.boot.data.jpa.model.inheritance;

import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;

@Entity(name = "stapler")
@DiscriminatorValue("stapler")
public class StaplerModel extends ProductModel {

private static final long serialVersionUID = -1370731097798172520L;

private Integer width;

private Integer height;

public StaplerModel() {
super();
}

public StaplerModel(String code, String name, String description, Integer width, Integer height) {
super(code, name, description);
this.width = width;
this.height = height;
}

public Integer getWidth() {
return width;
}

public void setWidth(Integer width) {
this.width = width;
}

public Integer getHeight() {
return height;
}

public void setHeight(Integer height) {
this.height = height;
}

@Override
public String toString() {
return "BookModel [width=" + width + ", height=" + height + ", toString()=" + super.toString() + "]";
}

}

测试

package com.school1024.spring.boot.data.jpa.feature;

import java.math.BigDecimal;

import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import com.school1024.spring.boot.data.jpa.SpringBootDataJpaTest;
import com.school1024.spring.boot.data.jpa.dao.inheritance.PenDao;
import com.school1024.spring.boot.data.jpa.dao.inheritance.ProductDao;
import com.school1024.spring.boot.data.jpa.dao.inheritance.StaplerDao;
import com.school1024.spring.boot.data.jpa.model.inheritance.PenModel;
import com.school1024.spring.boot.data.jpa.model.inheritance.ProductModel;
import com.school1024.spring.boot.data.jpa.model.inheritance.StaplerModel;

public class InheritanceTest extends SpringBootDataJpaTest {

@Autowired
private ProductDao productDao;

@Autowired
private PenDao penDao;

@Autowired
private StaplerDao staplerDao;

@Test
public void test() {
productDao.save(new ProductModel("N0001", "大白兔橡皮", "能当橡皮用,也能吃"));

penDao.save(new PenModel("N002", "钢笔", "送同事,送领导", new BigDecimal("0.8"), "万宝龙"));

staplerDao.save(new StaplerModel("N003", "得力订书器", "减压神器", 18, 4));
}
}

表截图:

这里需要介绍3个注解

@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.STRING)
@DiscriminatorValue("product")

@Inheritance 注解标记继承策略,可以项有3个:

  • SINGLE_TABLE:父类和所有子类都在一张表中。并创建一个字段来区分他们

  • TABLE_PER_CLASS:每个类型都有自己的表,互不干扰。

  • JOINED:父类和子类都有自己的表,和TABLE_PER_CLASS的区别是,子类中的父类属性值存储在父类表中。

@DiscriminatorColumn 注解用来指定区分数据的列名和列里面的值是什么

@DiscriminatorValue 注解指定每个类型的值

分享到