1. 程式人生 > >Hibernate深入學習(三):繼承與多型查詢,joined-subclass與union-subclass

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在更新父類表時效率低下