上篇文章中,只写了一些常见的映射文件编写。仅通过那几种来描述所有需求,似乎有点困难。现在,我们在来看一些其他的映射关系。
分别对以上几种文件进行介绍
继承映射又包括三种形式
什么意思呢?
继承映射处理的就是,表的结构大体相同,只不过是对于不同的对象来说,稍有不同。即:两种对象有重复的字段
对于以上的对象模型中,如何进行存储?而且,选择题和填空题中都有相同的属性。接下来,看一下对于该模型的存储。
存储结构,由名字就可以看出来了。该种方法就是用一张表来存储 选择题和 填空题 两种题型。即表结构如图:
映射文件编写:
这种方法,使用一个表来存储两类对象。里面会有空字段存在。而且这种情况需要在类中加入一个鉴别字段(名称),用于区分,该挑记录属于那个对象。
<?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>
需要注意的就是,必须给出鉴别字段。
这种方式,将会生成三张表。一张公用的数据表。两个各自的数据表。只不过是通过外键关联起来的。需要使用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>
每个具体类一张表。即取消上面那种方式 的外键关联。只生成 选择题,填空题 两张独立 不相关的表。需要使用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>
复合主键映射,在需求中会很多。但是发现人们用的不是很多。一般对于这种情况,人们会单独给出一个字段来作为主键。
当然,如果使用新字段来做主键的话。数据库可能会存在垃圾数据,人们只是参考符合主键,作为该表的逻辑主键。
如图:
类编写:
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的读取操作。