天天看点

ORM进阶:映射文件编写(下)-继承映射其他关联映射继承映射复合主键映射Component映射总结

       上篇文章中,只写了一些常见的映射文件编写。仅通过那几种来描述所有需求,似乎有点困难。现在,我们在来看一些其他的映射关系。

其他关联映射

  • 继承映射
  • 复合主键映射
  • Component映射

分别对以上几种文件进行介绍

继承映射

继承映射又包括三种形式

  • 一颗继承树一张表
  • 每个子类一张表
  • 每个具体类一张表

什么意思呢?

       继承映射处理的就是,表的结构大体相同,只不过是对于不同的对象来说,稍有不同。即:两种对象有重复的字段

举个例子:

       比如说,在题库的对象关系模型中:

ORM进阶:映射文件编写(下)-继承映射其他关联映射继承映射复合主键映射Component映射总结

       对于以上的对象模型中,如何进行存储?而且,选择题和填空题中都有相同的属性。接下来,看一下对于该模型的存储。

一颗继承树一张表

存储结构,由名字就可以看出来了。该种方法就是用一张表来存储 选择题和 填空题 两种题型。即表结构如图:

ORM进阶:映射文件编写(下)-继承映射其他关联映射继承映射复合主键映射Component映射总结

映射文件编写:

       这种方法,使用一个表来存储两类对象。里面会有空字段存在。而且这种情况需要在类中加入一个鉴别字段(名称),用于区分,该挑记录属于那个对象。

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.demo.hibernate.QuestionBank">
    <class name="QuestionBank" table="questionBank" lazy="false">
        <id name="QuestionId">
            <generator class="native"/>
        </id>
        <!-- 需要添加一个鉴别字段  注意 :小写string -->
        <discriminator column="QuestionTypeName" type="string"/>
        <property name="MainQuestion"/>  <!--题干-->
        <property name="CorrectAnswer"/>
        <property name="Remark"/>
        <!--编写 子类 对象的属性-->
        <subclass name="ChooseQuestion" discriminator-value="选择题">
            <property name="optionNumber"/>
            <property name="optionContent"/>
            <property name="isSingle"/>
        </subclass>
        <!--编写 子类 对象的属性-->
        <subclass name="BlankQuestion" discriminator-value="填空题">
            <property name="blankNumber"/>
            <property name="IsOrder"/>   <!--是否乱序-->
        </subclass>
    </class>
</hibernate-mapping>
           

需要注意的就是,必须给出鉴别字段。

每个子类一张表

ORM进阶:映射文件编写(下)-继承映射其他关联映射继承映射复合主键映射Component映射总结

       这种方式,将会生成三张表。一张公用的数据表。两个各自的数据表。只不过是通过外键关联起来的。需要使用joined-subclass属性,来生成子类表。

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.demo.hibernate.QuestionBank">
    <class name="QuestionBank" table="questionBank" lazy="false">
        <id name="QuestionId">
            <generator class="native"/>
        </id>
        <property name="MainQuestion"/>  <!--题干-->
        <property name="CorrectAnswer"/>
        <property name="Remark"/>
        <!--编写 子类 的属性,使用 joined-subclass生成子类表-->
        <joined-subclass name="ChooseQuestion" table="chooseQuestion">
            <key column="pid"/>
            <property name="optionNumber"/>
            <property name="optionContent"/>
            <property name="isSingle"/>
        </joined-subclass>
        <!--编写 子类 对象的属性,使用 joined-subclass生成子类表-->
        <joined-subclass name="BlanQuestion" table="blankQuestion">
            <key column="pid"/>
            <property name="blankNumber"/>
            <property name="IsOrder"/>   <!--是否乱序-->
        </joined-subclass>
    </class>
</hibernate-mapping>
           

每个具体类一张表

ORM进阶:映射文件编写(下)-继承映射其他关联映射继承映射复合主键映射Component映射总结

       每个具体类一张表。即取消上面那种方式 的外键关联。只生成 选择题,填空题 两张独立 不相关的表。需要使用union-subclass属性编写。

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.demo.hibernate.QuestionBank">
    <class name="QuestionBank" table="questionBank" abstract="true">
        <id name="id">
            <!--必须手动分配,如果使用native 将会出现数据不一致-->
            <!--可以使用GUID-->
            <generator class="assigned"/>
        </id>
        <property name="MainQuestion"/>  <!--题干-->
        <property name="CorrectAnswer"/>
        <property name="Remark"/>
        <union-subclass name="ChooseQuestion" table="chooseQuestion">
            <property name="optionNumber"/>
            <property name="optionContent"/>
            <property name="isSingle"/>
        </union-subclass>
        <union-subclass name="BlankQuestion" table="blankQuestion">
            <property name="blankNumber"/>
            <property name="IsOrder"/>   <!--是否乱序-->
        </union-subclass>
    </class>
</hibernate-mapping>
           

优劣对比

       第一种方式,如果子类中有非空字段。那么该表不能设置非空。所以会出现这种问题。而且冗余字段多。但是,这种方式,维护简单,只需要操作一张表。

       第二种方式,完全符合关系模型的设计原则,且不存在冗余,维护起来比较方便。对每个类的修改只需要修改其所对应的表,灵活性很好,完全是参照对象继承的方式进行配置,对于父类的查询需要使用左外链接,对于子类查询需要使用内链接,对于子类的持久话至少要处理两个表

       第三种方式,每个具体类对应一张表,有多少具体类就需要建立多少个独立的表。但是如果需要对基类进行修改,则需要对基类以及该类的子类所对应的所有表都进行修改。

小结

       以上讲了 三种方式,来处理继承关系的映射文件编写。各有优缺点。根据自己的需求,进行选择。

复合主键映射

这种情况,图就不展示了吧。使用一个composite-id来设置即可。

<?xml version="1.0"?>
<!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.demo.hibernate.FiscalYearPeriod" table="t_fiscal_year_period">
        <!--使用两个字段作为 主键-->
        <composite-id name="fiscalYearPeriodPK">
            <key-property name="fiscalYear"/>
            <key-property name="fiscalPeriod"/>
        </composite-id>
        <!--普通属性-->
        <property name="beginDate" type="date"/>
        <property name="endDate" type="date"/>
        <property name="periodSts"/>
    </class>
</hibernate-mapping>
           

       复合主键映射,在需求中会很多。但是发现人们用的不是很多。一般对于这种情况,人们会单独给出一个字段来作为主键。

       当然,如果使用新字段来做主键的话。数据库可能会存在垃圾数据,人们只是参考符合主键,作为该表的逻辑主键。

Component映射

如图:

ORM进阶:映射文件编写(下)-继承映射其他关联映射继承映射复合主键映射Component映射总结

类编写:

public class User {

    private int id; 
    private String name;    
    private Contact userContact;

    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Contact getUserContact() {
        return userContact;
    }
    public void setUserContact(Contact userContact) {
        this.userContact = userContact;
    }   
}
           

映射文件:

<?xml version="1.0"?>
<!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.demo.hibernate.User" table="user">
        <id name="id">
            <generator class="native"/>
        </id>
        <property name="name"/>
        <component name="employeeContact">
            <property name="email"/>
            <property name="address"/>
            <property name="contactTel"/>
        </component>
    </class>
</hibernate-mapping>
           

这种映射,其实就是为了简写 映射文件。

       比如说,是否可用,时间戳,操作人等等 。这些属性,每张表都需要。所以将这些属性,封装成一个类。这样,在编写子类的时候,只需要加上这个类,就可以生成该类内的属性了。

总结

       掌握了基础的几种映射之后,在了解以上几种映射。构建系统的对象关系模型,编写映射文件,基本就没有问题了。

       映射文件编写完成,对象模型有了,剩下的就是如何使用了。即:对hibernate的读取操作。

继续阅读