注:这里所说的实体指的是@Entity注解的类

继承映射使用@Inheritance来注解。它的strategy属性的取值由枚举InheritanceType来定义(包含SINGLE_TABLE、TABLE_PER_CLASS、JOINED。分别相应三种继承策略)。@Inheritance注解仅仅能作用于继承结构的超类上。假设不指定继承策略,默认使用SINGLE_TABLE。

JPA提供了三种继承映射策略:

1、 一个类继承结构一个表的策略。这是继承映射的默认策略。

即假设实体类B继承实体类A,实体类C也继承自实体A。那么仅仅会映射成一个表,这个表中包含了实体类A、B、C中全部的字段,JPA使用一个叫做“discriminator列”来区分某一行数据是应该映射成哪个实体。注解为:@Inheritance(strategy = InheritanceType.SINGLE_TABLE)

2、 联合子类策略。这样的情况下子类的字段被映射到各自的表中,这些字段包含父类中的字段,并运行一个join操作来实例化子类。注解为:@Inheritance(strategy = InheritanceType.JOINED)

3、 每一个详细的类一个表的策略。注解为:@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)



一、一个类继承结构一个表的策略

这样的策略中。一个继承结构中的全部类都被映射到一个表中。该表中有一列被当作“discriminator列”。即使用该列来识别某行数据属于某个指定的子类实例。

这样的映射策略对实体和涉及类继承结构的查询的多态系统提供了非常好的支持。

但缺点是要求与子类的指定状态相应的列能够为空。

实比例如以下:

package com.mikan;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table; @Entity
@Table(name = "EMP")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "emp_type")
public class Employee implements Serializable { private static final long serialVersionUID = -7674269980281525370L; @Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
protected Integer empId; @Column
protected String name; // getter/setter方法 } package com.mikan; import javax.persistence.Column;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity; @Entity
@DiscriminatorValue("FT")
public class FullTimeEmployee extends Employee { private static final long serialVersionUID = 9115429216382631425L; @Column
private Double salary; // getter/setter方法 } package com.mikan; import javax.persistence.Column;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity; @Entity
@DiscriminatorValue("PT")
public class PartTimeEmployee extends Employee { private static final long serialVersionUID = -6122347374515830424L; @Column(name = "hourly_wage")
private Float hourlyWage; // getter/setter方法 }

当中,超类的@DiscriminatorColumn注解能够省略,默认的“discriminator列”名为DTYPE,默认类型为STRING。

@DiscriminatorColumn注解仅仅能使用在超类上,不能使用到详细的子类上。

discriminatorType的值由DiscriminatorType枚举定义,包含STRING、CHAR、INTEGER。假设指定了discriminatorType,那么子类上@ DiscriminatorValue注解的值也应该是对应类型。

@DiscriminatorValue注解仅仅能使用在详细的实体子类上。

相同@DiscriminatorValue注解也能够省略,默认使用类名作为值。

上面的样例中。仅仅会生成一个表,包括了字段emp_type、empId、name、salary、hourly_wage。当保存FullTimeEmployee时。emp_type的值为“FT”。 当保存PartTimeEmployee时,emp_type的值为“PT”。



二、联合子类策略

这样的策略超类会被映射成一个单独的表。每一个子类也会映射成一个单独的表。子类相应的表中仅仅包含自身属性相应的字段,默认情况下使用主键作为超类相应的表的外键。

这样的策略对于实体间的多态关系提供了非常好的支持。

但缺点是实例化子类实例时须要一个或多个表的关联操作。

在深层次的继承结构中,这会导致性能非常低。

实比例如以下:

package com.mikan;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table; @Entity
@Table(name = "EMP")
@Inheritance(strategy = InheritanceType.JOINED)
public class Employee implements Serializable { private static final long serialVersionUID = -7674269980281525370L; @Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
protected Integer empId; @Column
protected String name; // getter/setter方法 } package com.mikan; import javax.persistence.Column;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.Table; @Entity
@Table(name = "FT_EMP")
public class FullTimeEmployee extends Employee { private static final long serialVersionUID = 9115429216382631425L; @Column
private Double salary; // getter/setter方法 } package com.mikan; import javax.persistence.Column;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.Table; @Entity
@Table(name = "PT_EMP")
public class PartTimeEmployee extends Employee { private static final long serialVersionUID = -6122347374515830424L; @Column(name = "hourly_wage")
private Float hourlyWage; // getter/setter方法 }

这会映射成三个详细的表。各自是,Employee相应EMP表,字段包含empId、name;FullTimeEmployee相应FT_EMP表,字段包含empId、salary;PartTimeEmployee相应PT_EMP表,字段包含empId、hourly_wage。

当中。表FT_EMP和PT_EMP中的empId作为表EMP的外键,同是它也是主键。默认情况下,使用超类的主键作为子类的主键和外键。

当然。能够通过@PrimaryKeyJoinColumn注解来自己指定外键的名称,如FullTimeEmployee使用@PrimaryKeyJoinColumn(name
= "FT_EMPID")注解,那么该子类实体的字段为FT_EMPID、name。FT_EMPID作为表FT_TIME的主键,同一时候它也是EMP表的外键。

子类实体每保存一条数据。会在EMP表中插入一条记录。如FT_EMP表插入一条数据,会先在EMP表中插入name,并生成empId。再在FT_EMP表中插入empId和salary。PT_EMP同理。

无论超类是抽象类还是详细类。都会生成相应的表。

三、每一个详细的类一个表的策略

这样的映射策略每一个类都会映射成一个单独的表。类的全部属性。包含继承的属性都会映射成表的列。

这样的映射策略的缺点是:对多态关系的支持有限。当查询涉及到类继承结构时通常须要发起SQL UNION查询。

实比例如以下:

package com.mikan;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table; @Entity
@Table(name = "EMP")
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Employee implements Serializable { private static final long serialVersionUID = -7674269980281525370L; @Id
@GeneratedValue(strategy = GenerationType.TABLE)
protected Integer empId; @Column
protected String name; // getter/setter方法 } package com.mikan; import javax.persistence.Column;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.Table; @Entity
@Table(name = "FT_EMP")
public class FullTimeEmployee extends Employee { private static final long serialVersionUID = 9115429216382631425L; @Column
private Double salary; // getter/setter方法 } package com.mikan; import javax.persistence.Column;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.Table; @Entity
@Table(name = "PT_EMP")
public class PartTimeEmployee extends Employee { private static final long serialVersionUID = -6122347374515830424L; @Column(name = "hourly_wage")
private Float hourlyWage; // getter/setter方法 }

这会映射成三个详细的表,各自是,Employee相应EMP表,字段包含empId、name;FullTimeEmployee相应FT_EMP表,字段包含empId、salary;PartTimeEmployee相应PT_EMP表。字段包含empId、hourly_wage。当中,表FT_EMP和PT_EMP中的empId和EMP表的empId没有不论什么关系。子类实体每保存一条数据,EMP表中不会插入记录。

并且主键的生成策略不能使用GenerationType.AUTO或GenerationType.IDENTITY。否则会出现异常:

org.hibernate.MappingException: Cannot use identity column key generation with <union-subclass> mapping for: com.mikan.PartTimeEmployee

由于TABLE_PER_CLASS策略每一个表都是单独的,没有而且各表的主键没有不论什么关系。所以不能使用GenerationType.AUTO或GenerationType.IDENTITY主键生成策略,能够使用GenerationType.TABLE。

详细可參考:http://stackoverflow.com/questions/916169/cannot-use-identity-column-key-generation-with-union-subclass-table-per-clas

假设超类是抽象类,那么不会生成相应的表。假设超类是详细的类,那么会生成相应的表。

以上实例使用JPA的hibernate实现測试通过。

JPA实体继承实体的映射策略的更多相关文章

  1. Hibernate JPA实体继承的映射(二) @MappedSuperclass

    基于代码复用和模型分离的思想,在项目开发中使用JPA的@MappedSuperclass注解将实体类的多个属性分别封装到不同的非实体类中. 1.@MappedSuperclass注解只能标准在类上:@ ...

  2. Hibernate JPA实体继承的映射(一) 概述

    http://www.cnblogs.com/yingsong/p/5179975.html   注:文章中据说的实体指的是被@Entity注解的类. JPA中对象关系映射通常情况下是一个实体对应一个 ...

  3. JPA实体继承映射

    注意:据说,在本文所指的实体是@Entity注解的类. JPA在对象 - 关系映射通常情况下一个实体对应表,不管是什么这两个实体之间的关系.假设两个实体之间的继承关系.那么它是如何映射? JPA实体支 ...

  4. JavaEE(15) - JPA实体继承

    1. 实体继承映射的三种策略 #1. 整个类层次对应一张表 #2. 连接子类 #3. 每个具体类对应一张表 2. 使用抽象实体 3. 使用非实体父类 4. 重定义子类实体的外键列 ---------- ...

  5. 缓存策略 半自动化就是mybaitis只支持数据库查出的数据映射到pojo类上,而实体到数据库的映射需要自己编写sql语句实现,相较于hibernate这种完全自动化的框架我更喜欢mybatis

    springboot入门(三)-- springboot集成mybatis及mybatis generator工具使用 - FoolFox - CSDN博客 https://blog.csdn.net ...

  6. Spring Data Jpa系列教程--------实体解析和关联关系

    Spring Data Jpa是基于HIbernate开发的,所以建立实体建的实体和映射关系需要好好好的去了解一下,本文有以下内容,实体管理器介绍,实体与数据库表的映射介绍,关联关系(一对多,多对多) ...

  7. Code First的实体继承模式

    Entity Framework的Code First模式有三种实体继承模式 1.Table per Type (TPT)继承 2.Table per Class Hierarchy(TPH)继承 3 ...

  8. Entity Framework应用:Code First的实体继承模式

    Entity Framework的Code First模式有三种实体继承模式 1.Table per Type (TPT)继承 2.Table per Class Hierarchy(TPH)继承 3 ...

  9. 接口是否可继承接口? 抽像类是否可实现(implements)接口? 抽像类是否可继承实体类(concrete class)?

    接口是否可继承接口? 抽像类是否可实现(implements)接口? 抽像类是否可继承实体类(concrete class)? 1. 接口可以继承接口. 2. 抽像类可以实现(implements)接 ...

随机推荐

  1. andriod 文本居中: android:gravity="center"

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools=&q ...

  2. 求助关于jquery easyUI中的treegrid组件,请各位帮忙给个思路,谢谢啦

    现在项目中用到jquery easyUI中的treegrid组件,已经可以正常显示了.但是在保存的时候遇到问题,页面上参照官网的例子可以在页面更新,但是怎么获取编辑后的数据进而保存到数据库呢?

  3. python opencv 人脸识别

    def findface(image): import cv2  frame=cv2.imread('n1.jpg') classifier=cv2.CascadeClassifier("h ...

  4. [PHP] Ubuntu 16.10 开启PHP错误提示

    两个步骤: 修改php.ini配置文件中的error_reporting 和 display_errors两地方内容: sudo vim /etc/php/7.0/apache2/php.ini er ...

  5. 从volatile说到i++的线程安全问题

    简介 volatile关键字保证了在多线程环境下,被修饰的变量在别修改后会马上同步到主存,这样该线程对这个变量的修改就是对所有其他线程可见的,其他线程能够马上读到这个修改后值. Thread的本地内存 ...

  6. 【BZOJ】【2434】【NOI2011】阿狸的打字机

    AC自动机+DFS序+BIT 好题啊……orz PoPoQQQ 大爷 一道相似的题目:[BZOJ][3172][TJOI2013]单词 那道题也是在fail树上数有多少个点,只不过这题是在x的fail ...

  7. 阿里的STORM——JSTORM

    看介绍文档貌似挺好:https://github.com/alibaba/jstorm   阿里拥有自己的实时计算引擎 类似于hadoop 中的MR 开源storm响应太慢 开源社区的速度完全跟不上A ...

  8. Restful安全认证及权限的解决方案

    一.Restful安全认证常用方式 1.Session+Cookie 传统的Web认证方式.需要解决会话共享及跨域请求的问题. 2.JWT JSON Web Token. 3.OAuth 支持两方和三 ...

  9. relatedTarget、fromElement、toElement相关元素

    在发生mouseover和mouseout事件时,还会涉及更多的元素.这两个事件都会涉及把鼠标指针从一个元素的边界之内移到另一个元素边界之内.对mouseover事件而言,事件的主目标是获得光标的元素 ...

  10. 开源 java CMS - FreeCMS2.2 网站管理

    项目地址:http://www.freeteam.cn/ 网站管理 FreeCMS支持站点群模式,并支持无限树级管理. 网站的相关文件在site文件夹下,每一个网站有自己的文件夹,源文件文件夹名就是自 ...