文档章节

[翻译] hibernate映射继承关系(一):一张表对应一整棵类继承树

lwei
 lwei
发布于 2012/05/22 16:34
字数 1414
阅读 1.9K
收藏 3

英文原址

网上这个主题的文章不在少数,这个系列的文章的部分价值在于给出了注解模式(Annotation)的例子。文章易懂,权当增强记忆,捎带着练习下翻译(翻译不当之处请指出)。  

Hibernate中继承关系的简介

java是一种面向对象语言,它可以实现继承关系。然而,继承却是"对象模型-关系模型"不匹配的最显而易见的方面之一。面向对象系统能够轻松的对“is a”和“has a”关系进行建模。而关系模型只能表达两个实体间的"has a"关系。hibernate能够把有关联的表映射为对象,但你需要根据需要来选择不同的映射策略。

Hibernate继承关系映射策略分为三种:一张表对应一整棵类继承树、一个类对应一张表、每一个具体类对应一张表。

之一:一张表对应一整棵类继承树(子类和父类共享同一张表)

假设我们有一个 Person 类及其子类 Employee. 每个类包括如下属性:

* class Person
        - firstname
        - lastname

* class Employee
        - joining_date
        - department_name

在“一张表对应一整棵类继承树这种模式中,继承树上的所有类的数据都存储在一张表上,鉴别器字段(discriminator )是唯一的标识每个类的关键字段。

下面是“一张表对应一整棵类继承树模式的优点和缺点:

优点

这种模式提供了最好的性能,因为即使在深层继承的情况下,检索一条子类数据,也只需要一次select操作。

缺点

对于任何一个子类的变更,比如增删改某字段,都将导致数据库表的变更。 

建表语句

CREATE TABLE `person` (
    `person_id` BIGINT(10) NOT NULL AUTO_INCREMENT,
    `firstname` VARCHAR(50) NULL DEFAULT NULL,
    `lastname` VARCHAR(50) NULL DEFAULT NULL,
    `joining_date` DATE NULL DEFAULT NULL,
    `department_name` VARCHAR(50) NULL DEFAULT NULL,
    `discriminator` VARCHAR(20) NOT NULL,
    PRIMARY KEY (`person_id`)
)

PERSON表被用来同时存储 Employee  Person 对象. 

Hibernate 继承: XML 映射 

下面的例子展示了如何用XML方式映射  Employee  Person 实体类

Person.java 

package net.viralpatel.hibernate;
 
public class Person {
 
    private Long personId;
    private String firstname;
    private String lastname;
 
    // Constructors and Getter/Setter methods,
}

Employee.java

package net.viralpatel.hibernate;
 
import java.util.Date;
 
public class Employee extends Person {
 
    private Date joiningDate;
    private String departmentName;
 
    // Constructors and Getter/Setter methods,
}

Person.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
 
<hibernate-mapping package="net.viralpatel.hibernate">
 
    <class name="Person" table="PERSON" discriminator-value="P">
        <id name="personId" column="PERSON_ID">
            <generator class="native" />
        </id>
 
        <discriminator column="DISCRIMINATOR" type="string" />
 
        <property name="firstname" />
        <property name="lastname" column="lastname" />
 
        <subclass name="Employee" extends="Person" discriminator-value="E">
                <property name="departmentName" column="department_name" />
                <property name="joiningDate" type="date" column="joining_date" />
        </subclass>
    </class>
</hibernate-mapping>

注意这里只定义了一个 hibernate 映射文件 Person.hbm.xml.

Person  Employee 类都定义在这同一个文件中.

<discriminator> 标签用来指定鉴别器列,包括列名和类型.

<subclass> 标签用于映射子类 Employee. 注意我们没有用常规的 <class>标签来映射 Employee ,因为它位于继承关系树下端。

Person 类的鉴别器的值被指定为 “P” ,相应的 Employee “E”,这样Hibernate将要持久化person  employee时,相应的“P”“E”将被置入鉴别器字段。

 Hibernate 继承: 注解映射

 下面的例子展示了如何用JPA注解方式来映射 Employee  Person 实体类。

 Person.java 

package net.viralpatel.hibernate;
 
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.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;
 
@Entity
@Table(name = "PERSON")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(
    name="discriminator",
    discriminatorType=DiscriminatorType.STRING
)
@DiscriminatorValue(value="P")
public class Person {
 
    @Id
    @GeneratedValue
    @Column(name = "PERSON_ID")
    private Long personId;
 
    @Column(name = "FIRSTNAME")
    private String firstname;
 
    @Column(name = "LASTNAME")
    private String lastname;
 
    // Constructors and Getter/Setter methods,
}

Person 类是继承树的根类,所以我们使用了下面一些注解使其成为根类。

@Inheritance – 定义一个实体类继承树的继承策略,这个注解只能定义在继承树的根类上。

@DiscriminatorColumn – 用于当@Inheritance 的值被定义为 SINGLE_TABLE  JOINED 时,指定鉴别器列。 此注解只能用于两种类:一、继承树的根类,二、继承树的某子类,并且该子类定义了自己继承策略。

如果在需要鉴别器列的时候,没有使用@DiscriminatorColumn注解,那么鉴别器列的名称将默认为“DTYPE”,类型将默认为“STRING”。

@DiscriminatorValue – 用于指定给定实体类所对应的鉴别器列的具体值。 DiscriminatorValue 注解只能用在具体的实体类中。如果使用了鉴别器列,但是没有使用 DiscriminatorValue 注解,一个鉴别器值生成器将生效并产生一个鉴别器值来代表这个类。如果鉴别器列的类型是 STRING,  鉴别器列的值默认是该类的名称。如果不采用默认值,那么应该在继承树的每个类中都使用该注解。

 Employee.java 

package net.viralpatel.hibernate;
 
import java.util.Date;
 
import javax.persistence.Column;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.Table;
 
@Entity
@Table(name="PERSON")
@DiscriminatorValue("E")
public class Employee extends Person {
 
    @Column(name="joining_date")
    private Date joiningDate;
 
    @Column(name="department_name")
    private String departmentName;
 
    // Constructors and Getter/Setter methods,
}

Employee类是Person类的子类,所以在映射时,使用@DiscriminatorValue注解来定义鉴别器的值,此例中,“E”将被置入鉴别器列。 

 MainClass

 package net.viralpatel.hibernate;

import java.util.Date;
 
import org.hibernate.Session;
import org.hibernate.SessionFactory;
 
public class Main {
 
    public static void main(String[] args) {
 
        SessionFactory sf = HibernateUtil.getSessionFactory();
        Session session = sf.openSession();
        session.beginTransaction();
 
        Person person = new Person("Steve", "Balmer");
        session.save(person);
 
        Employee employee = new Employee("James", "Gosling", "Marketing", new Date());
        session.save(employee);
 
        session.getTransaction().commit();
        session.close();
 
    }
}

Main class 用来持久化 Person     Employee类的实例。注意两个类都存储在PERSON表中,鉴别器列用于区分两个实体。

 输出结果

Hibernate: insert into EMPLOYEE (FIRSTNAME, LASTNAME, discriminator) values (?, ?, 'P')
Hibernate: insert into EMPLOYEE (FIRSTNAME, LASTNAME, department_name, joining_date, discriminator) values (?, ?, ?, ?, 'E')

 

需要例子中完整代码的,原文连接中提供有下载。

© 著作权归作者所有

lwei

lwei

粉丝 40
博文 19
码字总数 8066
作品 0
郑州
高级程序员
私信 提问
加载中

评论(0)

新手上路之Hibernate(5):继承映射

之前的几篇文章主要介绍的是关系映射。之所以用好几篇的文章来介绍关系映射,其重要性与常用行可见一斑。还有一种映射,也就是今天要介绍的——继承映射,也是很重要的一种映射模式。 一、继...

Airship
2016/12/12
0
0
【SSH系列】Hibernate映射 -- 继承映射

开篇前言 在前面的博文中,小编介绍了hibernate中的映射,一对一,一对多,多对多,单向,双向等,今天这篇博文,小编主要来介绍一下hibernate中的继承映射,小伙伴都知道在C#中,如果想要实...

丁国华
04/01
0
0
Java程序员从笨鸟到菜鸟之(五十五)细谈Hibernate(六)Hibernate继承关系映射

在面向对象的程序领域中,类与类之间是有继承关系的,例如Java世界中只需要extends关键字就可以确定这两个类的父子关系,但是在关系数据库的世界 中,表与表之间没有任何关键字可以明确指明这...

长平狐
2012/11/12
144
0
Hibernate学习4--Hibernte的映射关系(二)

上一节我们主要研究下了Hibernate中的一一映射和多对一映射,这节我们看下Hibernate中的其他几种映射,包括一对多映射,多对多映射,复合主键映射及继承映射。 第一种是一对多映射,“一对多...

王小明123
2014/04/20
96
0
【Java】Hibernate(四)对象/关系数据库映射基础

【映射】 对象和关系数据库之间的映射通常是用一个XML文档来定义的。映射文档被设计为易读的,并且可以手工修改。映射语言以Java为中心,这就意味着映射文档是按照持久化类的定义来创建的,而...

王璐-Louise
04/01
0
0

没有更多内容

加载失败,请刷新页面

加载更多

基于 Roslyn 实现解析引擎

基于 Roslyn 实现一个简单的条件解析引擎 最近在做一个勋章的服务,我们想定义一些勋章的获取条件,满足条件之后就给用户颁发一个勋章,定义条件的时候会定义需要哪些参数,参数的类型,获取...

osc_mfth2zpa
18分钟前
43
0
将字符串中的字母全部转换为大写字母/小写字母

<script> let str = "Hello World!"; // 将字符串的字符全部转换为小写字符 function lowerCase(str) { let arr = str.split(""); let newStr = ""; //......

osc_xsr0bfp3
19分钟前
30
0
Vue 商城的一些小demo(后台添加商品、前台购物车、本地存储的使用)

demo 商城后台,添加一种商品 <!DOCTYPE html><html> <head> <meta charset="utf-8" /> <title></title> <!-- 引入vue.js --> <script src="js/vue.js......

osc_h8lo50ya
21分钟前
37
0
Git使用教程

Git使用教程 一:Git是什么? Git是目前世界上最先进的分布式版本控制系统。 二:SVN与Git的最主要的区别? SVN是集中式版本控制系统,版本库是集中放在中央服务器的,而干活的时候,用的都是...

osc_c9pkd6zt
22分钟前
36
0
文件夹损坏无法打开如何恢复

问题描述: 目录损坏说明这个文件夹内部结构损坏了。文件夹损坏无法打开如何恢复具体恢复方法可以看正文了解(不格式化的恢复方法)。 工具/软件:极限数据恢复软件 步骤1:先百度搜索并下载...

osc_6mbnx553
22分钟前
44
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部