Hibernate继承映射_JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > Hibernate继承映射

Hibernate继承映射

 2012/2/16 9:09:54  kilowen  程序员俱乐部  我要评论(0)
  • 摘要:在面向对象的程序领域中,类与类之间是有继承关系的,例如Java世界中只需要extends关键字就可以确定这两个类的父子关系,但是在关系数据库的世界中,表与表之间没有任何关键字可以明确指明这两张表的父子关系,表与表是没有继承关系这样的说法的。为了将程序领域中的继承关系反映到数据中,Hibernate为我们提供了3中方案:第一种方案:一个子类对应一张表。第二种方案:使用一张表表示所有继承体系下的类的属性的并集。第三种方案:每个子类使用一张表只存储它特有的属性
  • 标签:继承 hibernate
    在面向对象的程序领域中,类与类之间是有继承关系的,例如Java世界中只需要extends关键字就可以确定这两个类的父子关系,但是在关系数据库的世界中,表与表之间没有任何关键字可以明确指明这两张表的父子关系,表与表是没有继承关系这样的说法的。为了将程序领域中的继承关系反映到数据中,Hibernate为我们提供了3中方案:
第一种方案:一个子类对应一张表。
第二种方案:使用一张表表示所有继承体系下的类的属性的并集。
第三种方案:每个子类使用一张表只存储它特有的属性,然后与父类所对应的表以一对一主键关联的方式关联起来。

现在假设有People、Student、Teacher三个类,父类为People,Student与Teacher为People的父类,代码如下:
People类:
public class People
{
    /*父类所拥有的属性*/
    private String id;
    private String name;
    private String sex;
    private String age;
    private Timestamp birthday;
    
    /*get和set方法*/
}


Student类:
public class Student extends People
{
    /*学生独有的属性*/
    private String cardId;//学号

    public String getCardId()
    {
        return cardId;
    }

    public void setCardId(String cardId)
    {
        this.cardId = cardId;
    }
}


Teacher类:
public class Teacher extends People
{
    /*Teacher所独有的属性*/
    private int salary;//工资

    public int getSalary()
    {
        return salary;
    }

    public void setSalary(int salary)
    {
        this.salary = salary;
    }
}



第一种方案:一个子类对应一张表
该方案是使继承体系中每一个子类都对应数据库中的一张表。示意图如下:


  每一个子类对应的数据库表都包含了父类的信息,并且包含了自己独有的属性。每个子类对应一张表,而且这个表的信息是完备的,即包含了所有从父类继承下来的属性映射的字段。这种策略是使用<union-subclass>标签来定义子类的。
配置People.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>
    <class name="com.suxiaolei.hibernate.pojos.People" abstract="true">
        <id name="id" type="string">
            <column name="id"></column>
            <generator class="uuid"></generator>
        </id>

        <property name="name" column="name" type="string"></property>
        <property name="sex" column="sex" type="string"></property>
        <property name="age" column="age" type="string"></property>
        <property name="birthday" column="birthday" type="timestamp"></property>

        <!-- 
        <union-subclass name="com.suxiaolei.hibernate.pojos.Student" table="student"> 
            <property name="cardId" column="cardId" type="string"></property> 
        </union-subclass> 
        <union-subclass name="com.suxiaolei.hibernate.pojos.Teacher" table="teacher"> 
            <property name="salary" column="salary" type="integer"></property> 
        </union-subclass> 
        -->
    </class>
    <union-subclass name="com.suxiaolei.hibernate.pojos.Student"
        table="student" extends="com.suxiaolei.hibernate.pojos.People">
        <property name="cardId" column="cardId" type="string"></property>
    </union-subclass>

    <union-subclass name="com.suxiaolei.hibernate.pojos.Teacher"
        table="teacher" extends="com.suxiaolei.hibernate.pojos.People">
        <property name="salary" column="salary" type="integer"></property>
    </union-subclass>
</hibernate-mapping>


  以上配置是一个子类一张表方案的配置,<union-subclass>标签是用于指示出该hbm文件所表示的类的子类,如People类有两个子类,就需要两个<union-subclass>标签以此类推。<union-subclass>标签的"name"属性用于指定子类的全限定名称,"table"属性用于指定该子类对应的表的名称,"extends"属性用于指定该子类的父类,注意该属性与<union-subclass>标签的位置有关,若 <union-subclass>标签作为<class>标签的子标签,则"extends"属性可以不设置,否则需要明确设置"extends"属性。<class>标签中的"abstract"属性如果值为true则,不会生成表结构。如果值为false则会生成表结构,但是不会插入数据。
根据People.hbm.xml生成表结构:
 
 drop table if exists student
   drop table if exists teacher

    create table student (
        id varchar(255) not null,
        name varchar(255),
        sex varchar(255),
        age varchar(255),
        birthday datetime,
        cardId varchar(255),
        primary key (id)
    )

    create table teacher (
        id varchar(255) not null,
        name varchar(255),
        sex varchar(255),
        age varchar(255),
        birthday datetime,
        salary integer,
        primary key (id)
    )

可以看到一个子类对应一张表。

第二种方案:使用一张表表示所有继承体系下的类的属性的并集
  这种策略是使用<subclass>标签来实现的。因为类继承体系下会有许多个子类,要把多个类的信息存放在一张表中,必须有某种机制来区分哪些记录是属于哪个类的。Hibernate中的这种机制就是,在表中添加一个字段,用这个字段的值来进行区分。在表中添加这个标示列使用<discriminator>标签来实现。
该策略的示意图:


将继承体系中的所有类信息表示在同一张表中后,只要是这个类没有的属性会被自动赋上null。
配置People.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>
    <class name="com.suxiaolei.hibernate.pojos.People" table="people">
        <id name="id" type="string">
            <column name="id"></column>
            <generator class="uuid"></generator>
        </id>

        <discriminator column="peopleType" type="string"></discriminator>

        <property name="name" column="name" type="string"></property>
        <property name="sex" column="sex" type="string"></property>
        <property name="age" column="age" type="string"></property>
        <property name="birthday" column="birthday" type="timestamp"></property>

        <subclass name="com.suxiaolei.hibernate.pojos.Student" discriminator-value="student">
            <property name="cardId" column="cardId" type="string"></property>
        </subclass>
        
        <subclass name="com.suxiaolei.hibernate.pojos.Teacher" discriminator-value="teacher">
            <property name="salary" column="salary" type="string"></property>
        </subclass>
    </class>
</hibernate-mapping>


<discriminator>标签用于在表中创建一个标识列,其"column"属性指定标识列的列名,"type"指定了标识列的类型。<subclass>标签用于指定该HBM文件代表类的子类,有多少子类就有多少个该标签,其"name"属性指定子类的名称,"discriminator-value"属性指定该子类的数据的标识列的值是什么,其"extends"属性与<union-subclass>的"extends"属性用法一致。
根据People.hbm.xml生成表结构:
   
drop table if exists people

    create table people (
        id varchar(255) not null,
        peopleType varchar(255) not null,
        name varchar(255),
        sex varchar(255),
        age varchar(255),
        birthday datetime,
        cardId varchar(255),
        salary varchar(255),
        primary key (id)
    )

复制代码
可以看到一张表将继承体系下的所有信息都包含了,其中"peopleType"为标识列。

第三种方案:每个子类使用一张表只存储它特有的属性,然后与父类所对应的表以一对一主键关联的方式关联起来。
  这种策略是使用<joined-subclass>标签来定义子类的。父类、子类都对应一张数据库表。在父类对应的数据库表中,它存储了所有记录的公共信息,实际上该父类对应的表会包含所有的记录,包括父类和子类的记录;在子类对应的数据库表中,这个表只定义了子类中所特有的属性映射的字段。子类对应的数据表与父类对应的数据表,通过一对一主键关联的方式关联起来。
这种策略的示意图:


  people表中存储了子类的所有记录,但只记录了他们共有的信息,而他们独有的信息存储在他们对应的表中,一条记录要获得其独有的信息,要通过people记录的主键到其对应的子表中查找主键值一样的记录然后取出它独有的信息。
配置People.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>
    <class name="com.suxiaolei.hibernate.pojos.People" table="people">
        <id name="id" type="string">
            <column name="id"></column>
            <generator class="uuid"></generator>
        </id>

        <property name="name" column="name" type="string"></property>
        <property name="sex" column="sex" type="string"></property>
        <property name="age" column="age" type="string"></property>
        <property name="birthday" column="birthday" type="timestamp"></property>
        
        <joined-subclass name="com.suxiaolei.hibernate.pojos.Student" table="student">
            <key column="id"></key>
            <property name="cardId" column="cardId" type="string"></property>
        </joined-subclass>
        
        <joined-subclass name="com.suxiaolei.hibernate.pojos.Teacher" table="teacher">
            <key column="id"></key>
            <property name="salary" column="salary" type="integer"></property>
        </joined-subclass>
    </class>
</hibernate-mapping>


<joined-subclass>标签需要包含一个key标签,这个标签指定了子类和父类之间是通过哪个字段来关联的。
根据People.hbm.xml生成表结构:
  
 drop table if exists people
    drop table if exists student
    drop table if exists teacher

    create table people (
        id varchar(255) not null,
        name varchar(255),
        sex varchar(255),
        age varchar(255),
        birthday datetime,
        primary key (id)
    )

    create table student (
        id varchar(255) not null,
        cardId varchar(255),
        primary key (id)
    )

    create table teacher (
        id varchar(255) not null,
        salary integer,
        primary key (id)
    )

    alter table student 
        add index FK8FFE823BF9D436B1 (id), 
        add constraint FK8FFE823BF9D436B1 
        foreign key (id) 
        references people (id)

    alter table teacher 
        add index FKAA31CBE2F9D436B1 (id), 
        add constraint FKAA31CBE2F9D436B1 
        foreign key (id) 
        references people (id)


可以看到,父类对应的表保存公有信息,子类对应的表保存独有信息,子类和父类对应的表使用一对一主键关联的方式关联起来。
==================================================================================
注解方式


二,注解配置
1,一个继承结构一张表

/**
 * 一个继承结构一张表,通过鉴别器区分记录属于哪个子类
 * 基类
 * @author sunjun
 * @date 2010-9-9 下午04:16:31
 */
@Entity
@Table(name = "category_single")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "dtype", discriminatorType = DiscriminatorType.STRING)
public class BaseCategorySingle {

	private Integer id;
	private String name;

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name = "id")
	public Integer getId() {
		return id;
	}

	@Column(name = "name")
	public String getName() {
		return name;
	}

	// getter and setter ...
}


@Entity
@DiscriminatorValue(value = "category1")
public class Category1 extends BaseCategorySingle {
	private String value1;

	@Column(name = "value1")
	public String getValue1() {
		return value1;
	}

	public void setValue1(String value) {
		this.value1 = value;
	}
}


@Entity
@DiscriminatorValue(value = "category2")
public class Category2 extends BaseCategorySingle {
	private String value2;

	@Column(name = "value2")
	public String getValue2() {
		return value2;
	}

	public void setValue2(String value) {
		this.value2 = value;
	}
}


生成脚本
CREATE TABLE `category_single` (
  `dtype` varchar(31) NOT NULL,
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(255) default NULL,
  `value2` varchar(255) default NULL,
  `value1` varchar(255) default NULL,
  PRIMARY KEY  (`id`)
)



2,基类一张表,每个子类一张表

/**
 * 基类一张表,存放公共属性,每个子类一张表,存放扩展属性
 * 
 * @author 
 * @date 2010-9-9 下午04:16:31
 */
@Entity
@Table(name = "category_join")
@Inheritance(strategy = InheritanceType.JOINED)
public class BaseCategoryJoin {

	private Integer id;
	private String name;

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name = "id")
	public Integer getId() {
		return id;
	}

	@Column(name = "name")
	public String getName() {
		return name;
	}
	// getter and setter ...
}


@Entity
@PrimaryKeyJoinColumn(name = "c_id")
public class Category3 extends BaseCategoryJoin {
	private String value3;

	@Column(name = "value3")
	public String getValue3() {
		return value3;
	}

	public void setValue3(String value) {
		this.value3 = value;
	}
}


@Entity
@PrimaryKeyJoinColumn(name = "c_id")
public class Category4 extends BaseCategoryJoin {
	private String value4;

	@Column(name = "value4")
	public String getValue4() {
		return value4;
	}

	public void setValue4(String value) {
		this.value4 = value;
	}
}


SQL代码:
CREATE TABLE `category_join` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(255) default NULL,
  PRIMARY KEY  (`id`)
)
CREATE TABLE `category3` (
  `value3` varchar(255) default NULL,
  `c_id` int(11) NOT NULL,
  PRIMARY KEY  (`c_id`),
  KEY `FKD4C702D5E92DD3B3` (`c_id`),
  CONSTRAINT `FKD4C702D5E92DD3B3` FOREIGN KEY (`c_id`) REFERENCES `category_join` (`id`)
)
CREATE TABLE `category4` (
  `value4` varchar(255) default NULL,
  `c_id` int(11) NOT NULL,
  PRIMARY KEY  (`c_id`),
  KEY `FKD4C702D6E92DD3B3` (`c_id`),
  CONSTRAINT `FKD4C702D6E92DD3B3` FOREIGN KEY (`c_id`) REFERENCES `category_join` (`id`)
) 



3,基类无表,每个子类一张表
java代码:
/**
 * 基类无表,每个子类一张表,存放所有属性
 * 
 * @author 
 * @date 2010-9-9 下午04:16:31
 */
@MappedSuperclass
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class BaseCategoryMany {
	protected Integer id;
	private String name;

	@Id
	@Column(name = "id")
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	public Integer getId() {
		return id;
	}

	@Column(name = "name")
	public String getName() {
		return name;
	}
	// setter and getter ...
}


@Entity
@Table(name = "category5")
public class Category5 extends BaseCategoryMany {
	// 可以自己定义主键
	private String value5;

	@Column(name = "value5")
	public String getValue5() {
		return value5;
	}

	public void setValue5(String value) {
		this.value5 = value;
	}
}


@Entity
@Table(name = "category6")
public class Category6 extends BaseCategoryMany {
	// 可以自己定义主键
	private String value6;

	@Column(name = "value6")
	public String getValue6() {
		return value6;
	}

	public void setValue6(String value) {
		this.value6 = value;
	}
}


SQL代码:
CREATE TABLE `category5` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(255) default NULL,
  `value5` varchar(255) default NULL,
  PRIMARY KEY  (`id`)
) 
CREATE TABLE `category6` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(255) default NULL,
  `value6` varchar(255) default NULL,
  PRIMARY KEY  (`id`)
) 
发表评论
用户名: 匿名