zoukankan      html  css  js  c++  java
  • 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-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>

        可以看到,这种方式是连接的形式,与上一种方式不同的是将子类的属性和父类的属性分开存储,和上面一种方式类似的是,因为都有父类表的外键,子表中的主键也不能重复。

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

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

    组件映射

        以以下类图为例:

                

        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的映射文件。它与继承类似,都是为了复用;相比继承映射而言,不同点在于它将功能抽象出来,它的粒度更细,提供了更广的复用范围,与接口类似。

    总结

        到此为止大致给大家介绍了一下继承映射和组件映射,希望通过对比的方式,将二者的区别和类似展现出来,下篇博客会介绍一下复合主键映射和集合映射。

  • 相关阅读:
    细说WebSocket -- Node.js篇
    跨域CORS原理及调用具体示例
    详解5种跨域方式及其原理
    java后台对json格式数据的解析
    serializeArray()和.serialize()的区别、联系
    JSON.parse(),JSON.stringify(),jQuery.parseJSON()的用法
    Jquery 遍历数组之$().each方法与$.each()方法介绍
    JQuery.Ajax()的data参数类型
    并发,并行,进程,线程,同步,异步
    Java之控制反转和依赖注入
  • 原文地址:https://www.cnblogs.com/james1207/p/3358112.html
Copyright © 2011-2022 走看看