《三》混合使用“一个类继承体系一张表”和“每个子类一张表”
比如上面的例子,worker类可能属性很少,而farmer属性却很多,把两者都与person放在同一张表中,则显得表的 结构不是很合理,会有很多字段是null。所以我们可以把属性少的worker与person放在一张表中维护,而对farmer单独用一张表保存信息。
person.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 package="hibernate.extend" auto-import="false">
<class name="Person" table="person" discriminator-value="0">
<id name="id">
<generator class="native"/>
</id>
<discriminator column="type" type="int"/>
<property name="name"/>
<property name="age"/>
<subclass name="Worker" discriminator-value="1">
<property name="work_year"/>
</subclass>
<subclass name="Farmer" discriminator-value="2"> //鉴别器的默认值是类的名称,字符串类型
<join table="farmer">
<key column="person_id"/>
<property name="farm_name"/>
</join>
</subclass>
</class>
</hibernate-mapping>
执行以上代码,可能会出现问题,跟hibernate配置有关。我们在前面配置了:
<property name="hibernate.hbm2ddl.auto">create</property>
在每次启动应用的时候,会先到数据库中删除相应的表。首先删除farmer表,它可以正确删除,然后根据配置文件(配置文件中表明只有这两张表)又要去删除person表。在我们前面写每个子类对应一张表时,生成了三张表,他们当时还在数据库中(名字前后一样)。也即是说第一次运行时,删的farmer表其实是上面产生的farmer表。由于根据要求要去删除person表,这时就会报错。因为worker表尚未删除,先删除person表,会引起外键关联错误。
所以可以手动把相关表删掉,再运行就可以通过了。
产生的sql语句如下:
Hibernate: insert into person (name, age, work_year, type) values (?, ?, ?, 1)
Hibernate: insert into person (name, age, type) values (?, ?, 2)
Hibernate: insert into farmer (farm_name, person_id) values (?, ?)
数据库中的表结构为:
person表:
+----+------+--------+------+---------------+
| id | type | name | age | work_year |
+----+------+--------+------+---------------+
| 1 | 0 | person | 22 | NULL |
| 2 | 1 | worker | 30 | 11 |
| 3 | 2 | farmer | 31 | NULL |
+----+------+--------+------+-----------+
farmer表:
+-----------+------------------+
| person_id | farm_name |
+-----------+-------------------+
| 3 | little candy |
+-----------+-------------------+