Hibernate征途(五)之继承映射和组件映射

    之所以把这两种映射放到一起说,是因为二者都是以复用为目的,减少了代码和配置量,这是相同点;二者之间的不同点类似继承和实现的区别:继承的类是一个事物的抽象,而实现的接口仅仅是功能的抽象。

继承映射

    如上面所说,以下面类图为例:

    

    它的映射方式有三种,它们的类和属性相同,只是映射文件不同,当然也导致映射的数据结构也不同,先一下以上三个类,再根据映射文件的不同说明每种映射方式。

    Animal

public class Animal {
	private int id;
	private String name;
	private boolean sex;
        //省略getter和setter……
}

    Bird

public class Bird extends Animal {
		private int height;
		public int getHeight() {
			return height;
		}
		public void setHeight(int height) {
			this.height = height;
		}
}

    Pig

public class Pig extends Animal {
	private int weight;
	public int getWeight() {
		return weight;
	}
	public void setWeight(int weight) {
		this.weight = weight;
	}
}

    冗余

    先来看一下表结构。    

    

    很明显,这种方式是将Pig和Bird冗余到一张表,以类型字段区分开来,来看一下它的映射文件:

<hibernate-mapping >
	<class name="com.tgb.hibernate.Animal"  table="t_animal" >
		<id name="id">
			<generator class="native" />
		</id>
		<discriminator column="type"  type="string"  />
		<property name="name" />
		<property name="sex" />
		<subclass name="com.tgb.hibernate.Pig" discriminator-value="P" >
			<property name="weight" />
		</subclass>
		<subclass	name="com.tgb.hibernate.Bird" discriminator-value="B">
			<property name="height" />
		</subclass>
	</class>
	
</hibernate-mapping>

    不出所料,这种方式是将两个类以子类的方式嵌入到Animal中,形成一个大“类”,从而映射出一张表,从而将将父、子类的实例全部保存在同一张表内。需要注意的是,Discriminator必须要在subclass之前声明,这个容易理解:先制定规则,再分子类。

    联合

    同样,先来看一下库表结构。

    

    再来看一下映射文件:

<hibernate-mapping package="com.tgb.hibernate">
	<class name="com.tgb.hibernate.Animal"  table="t_animal"  abstract ="true" >
		<id name="id">
			<generator class="assigned" />
		</id>
		<property name="name" />
		<property name="sex" />
		<union-subclass name="Pig"  table="t_pig">
			<property name="weight"/>
		</union-subclass>
		<union-subclass name="Bird" table="t_bird">
			<property name="height"/>
		</union-subclass>
	</class>
</hibernate-mapping>

    如配置文件所示,这种方式是子类联合:子类实例的数据仅保存在子类表中,没有在父类表中有记录。当class标签中没有abstract="true"这个属性时,它也是三张表,当添加此属性后,会生成上述的表结构。

    需要注意的是,主键生成策略不能是identity,也不能是native,因为native会根据数据库选择identity或sequence方式,这是因为两个子类表中的主键不能相同,而identity则会导致这个结果。

    连接

    同样,来看一下表结构。

    Hibernate征途(五)之继承映射和组件映射_第1张图片

    再来看一下映射文件:

<hibernate-mapping package="com.tgb.hibernate">
	<class name="com.tgb.hibernate.Animal"  table="t_animal" >
		<id name="id">
			<generator class="native" />
		</id>
		<property name="name" />
		<property name="sex" />
		<joined-subclass name="Pig" table="t_pig">
			<key column="pid" />
			<property name="weight"/>
		</joined-subclass>
		<joined-subclass name="Bird" table="t_bird">
			<key column="bid"/>
			<property name="height"/>
		</joined-subclass>
	</class>
	
</hibernate-mapping>
    可以看到,这种方式是连接的形式,与上一种方式不同的是将子类的属性和父类的属性分开存储,和上面一种方式类似的是,因为都有父类表的外键,子表中的主键也不能重复。

    这种存储方式容易出现的问题是,如果继承树的深度很深,那么查询一个子类实例时,因为子类的数据依次保存在其多个父类中,需要跨越多个表,大大影响效率。

    这三种存储方式各有优劣,要根据实际情况具体分析使用。

组件映射

    以以下类图为例:

            Hibernate征途(五)之继承映射和组件映射_第2张图片

    Contact类在此的作用就是组件类,需要时引用即可。来看一下简写的类:

    Contact

public class Contact {

		private String email;
		private String address;
		private String zipcode;
		private String contactTel;
		//省略getter和setter……
}
    Employee

public class Employee {

		private int id;
		private String name;
		private Contact employeeContact;
                //省略getter和setter
}
    User

public class User {

	private int id;
	private String name;
	private Contact userContact;
        //省略getter和setter……
}

    再来看一下组件映射的表结构:

    

    但从表结构上来看,和上面的“联合子类”的继承映射类似。再来看一下User的映射文件(Employee类似):

<hibernate-mapping>
	<class name="com.tgb.hibernate.User" table="t_User">
		<id name="id">
			<generator class="native"/>
		</id>
		<property name="name"/>
		<component  name="userContact">
			<property name="email"/>
			<property name="address"/>
			<property name="zipcode"/>
			<property name="contactTel"/>
		</component>
	</class>
</hibernate-mapping>

    可以看到Contact此处仅仅是作为组件使用,它仅仅是一个值,而非实体,所以不用Contact的映射文件。它与继承类似,都是为了复用;相比继承映射而言,不同点在于它将功能抽象出来,它的粒度更细,提供了更广的复用范围,与接口类似。

总结

    到此为止大致给大家介绍了一下继承映射和组件映射,希望通过对比的方式,将二者的区别和类似展现出来,下篇博客会介绍一下数量和方向型的映射《 Hibernate征途(六)之数量和关系映射》。

你可能感兴趣的:(Hibernate征途(五)之继承映射和组件映射)