Hibernate深入學習(三):繼承與多型查詢,joined-subclass與union-subclass
在上一篇中,我們對hibernate中3種繼承有了初步瞭解,並對subclass進行了測試,以及知道了它的諸多缺點,這些缺點導致subclass在開發中並不常用,接下來我們看看剩下的兩種繼承方式:joined-subclass與union-subclass
本文中使用的實體類與測試程式碼同前篇,不再贅述
首先我們看看joined-class的實體對映檔案:主要看元素
<?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="cn.sina.join.subclass" auto-import="false">
<class name="Person" table="joined_person">
<id name="id" column="pid" length="10" type="java.lang.Integer">
<generator class="increment"></generator>
</id>
<property name="name" type="java.lang.String" length="32" not-null="true"></property>
<property name="age" type="java.lang.Integer" length="5" not-null="true"></property>
<joined-subclass name="Worker" table="joined_worker">
<key column="person_id"> </key>
<property name="job" type="java.lang.String" length="32"></property>
<property name="unit" type="java.lang.String" length="32"></property>
</joined-subclass>
</class>
</hibernate-mapping>
我們已經知道joined-subclass是會產生兩張表的,中的table用於指定子類表名,並且使用person_id來與父類表建立關聯
測試程式碼見前篇,插入的測試結果如下:
Hibernate:
select
max(pid)
from
joined_person
Hibernate:
insert
into
joined_person
(name, age, pid)
values
(?, ?, ?)
Hibernate:
insert
into
joined_person
(name, age, pid)
values
(?, ?, ?)
Hibernate:
insert
into
joined_worker
(job, unit, person_id)
values
(?, ?, ?)
可以看到發出了4條sql語句,除了第一句省略,其它共3條insert語句
因為joined-subclass採用的是父類表儲存父類欄位,子類表儲存子類欄位,用外來鍵關聯,
因此第一條insert語句對應的是session.save(person);
第二天insert語句是在 session.save(worker)時,將worker繼承自父類的欄位插入,
最後一條insert語句是插入將worker插入到子類表中,它直插入子類獨有的欄位
在做查詢時,請使用類全名的形式,例如:
session.createQuery("from cn.sina.join.subclass.Person").list();
查詢的結果如下:
Hibernate:
select
person0_.pid as pid1_,
person0_.name as name1_,
person0_.age as age1_,
person0_1_.job as job2_,
person0_1_.unit as unit2_,
case
when person0_1_.person_id is not null then 1
when person0_.pid is not null then 0
end as clazz_
from
joined_person person0_
left outer join
joined_worker person0_1_
on person0_.pid=person0_1_.person_id
Hibernate:
select
worker0_.person_id as pid1_,
worker0_1_.name as name1_,
worker0_1_.age as age1_,
worker0_.job as job2_,
worker0_.unit as unit2_
from
joined_worker worker0_
inner join
joined_person worker0_1_
on worker0_.person_id=worker0_1_.pid
[Person [id=1, name=tom, age=10], Worker [job=washer, unit=bj], Person [id=3, name=tom, age=10], Worker [job=washer, unit=bj]]
[Worker [job=washer, unit=bj], Worker [job=washer, unit=bj]]
可以看出查詢父類使用的是一個左外連線查詢,同時查詢出了子類,而查詢子類使用的是一個內連線查詢
最後一個是union-subclass,它和joined-subclass類似,它將父類對應一張表,子類對應一張表,此時的子類表包括了從父類中繼承的欄位,它的實體對映檔案如下:注意看
<?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="cn.sina.union.subclass" auto-import="false">
<class name="Person" table="union_person">
<id name="id" column="pid" length="10" type="java.lang.Integer">
<generator class="increment"></generator>
</id>
<property name="name" type="java.lang.String" length="32" not-null="true"></property>
<property name="age" type="java.lang.Integer" length="5" not-null="true"></property>
<union-subclass name="Worker" table="union_worker">
<property name="job" type="java.lang.String" length="32"></property>
<property name="unit" type="java.lang.String" length="32"></property>
</union-subclass>
</class>
</hibernate-mapping>
可以看出union-subclass只需要指定一個表名即可
插入測試結果很簡單,就是發出兩條inert語句,插入到對應的表中即可
Hibernate:
select
max(ids_.pid)
from
( select
pid
from
union_person
union
select
pid
from
union_worker
) ids_
Hibernate:
insert
into
union_person
(name, age, pid)
values
(?, ?, ?)
Hibernate:
insert
into
union_worker
(name, age, job, unit, pid)
values
(?, ?, ?, ?, ?)
查詢結果如下(hql也要使用類全名)
Hibernate:
select
person0_.pid as pid3_,
person0_.name as name3_,
person0_.age as age3_,
person0_.job as job4_,
person0_.unit as unit4_,
person0_.clazz_ as clazz_
from
( select
pid,
name,
age,
null as job,
null as unit,
0 as clazz_
from
union_person
union
select
pid,
name,
age,
job,
unit,
1 as clazz_
from
union_worker
) person0_
Hibernate:
select
worker0_.pid as pid3_,
worker0_.name as name3_,
worker0_.age as age3_,
worker0_.job as job4_,
worker0_.unit as unit4_
from
union_worker worker0_
[Person [id=1, name=tom, age=10], Worker [job=washer, unit=bj]]
[Worker [job=washer, unit=bj]]
我們著重看一下父類的查詢sql,比較有意思,它也將子類查詢出來了,它先通過union將兩張表聯合查詢,再從聯合查詢的結果中獲取結果。
最後分析下二者的缺點:
1.插入與查詢的效率都低下
2.union-subclass在更新父類表時效率低下