Hibernate入门08 - 继承映射1

本文介绍了一种在ORM中处理对象继承关系的映射策略,通过在共享表中使用识别字段来表示不同子类别的记录,实现了多态操作并考虑了性能因素。
 如果应用程序中的对象有继承的关系,我们可以有三种策略将这种关系映像至数据表上。
 最简单的方式就是给每个对象一个表格,如果父类别User中有field1、field2两个属性,其表格USER有FIELD1、FIELD2与之对 应,而子类别SubUser若继承了父类别的field1、field2属性,表格中SUBUSER中也要拥有FIELD1、FIELD2与之对应,这种方法的好处只有映射上的方便,很显然的,父类与子类共有的属性,会变成在数据库表格中重复的字段,而且很难实现多型操作,建议只有在不需要多型操作时使 用,要执行这种映射,为每一个子类别撰写一个映射文件就是了,没什么特别的设定。
 第二种方式是将所有继承同一父类别的对象储存在同一个表格中,表格中使用识别字段来表示某一列(row)是属于某个子类别或父类别,这种方式方便执行多型操作,而且兼具效能上的考量,在这个主题中我们将先说明这个方法。
 我们先来看看我们撰写的类别与继承关系,首先是父类别:
User.java
package onlyfun.caterpillar;
 
public class User {
    private String id;
    private String name;
    private String password;
 
    public String getId() {
       return id;
    }
 
    public String getName() {
        return name;
    }
  
    public String getPassword() {
        return password;
   }
 
    public void setId(String string) {
        id = string;
    }
 
    public void setName(String string) {
        name = string;
    }
  
    public void setPassword(String password) {
        this.password = password;
    }
}

 再来是继承User类别的两个子类别,首先是PowerUser类别:
PowerUser.java
package onlyfun.caterpillar;
 
public class PowerUser extends User {
    private int level;
    private String otherOfPower;
  
    public int getLevel() {
        return level;
    }
  
    public String getOtherOfPower() {
        return otherOfPower;
    }
  
    public void setLevel(int level) {
        this.level = level;
    }
  
    public void setOtherOfPower(String otherOfPower) {
        this.otherOfPower = otherOfPower;
    }
}

 下面是继承User类别的GuestUser类别:
GuestUser.java
package onlyfun.caterpillar;
 
public class GuestUser extends User {
    private String otherOfGuest;
  
    public String getOtherOfGuest() {
        return otherOfGuest;
    }
 
    public void setOtherOfGuest(String otherOfGuest) {
        this.otherOfGuest = otherOfGuest;
    }  
}

 映射文件中该如何撰写,由于这些类别将映像至同一个表格,我们使用discriminator作为每个类别记录在表格中的识别,先直接看看映像文件如何撰写:
User.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping
    PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
 
<hibernate-mapping>
 
    <class name="onlyfun.caterpillar.User" table="USER" discriminator-value="ParentUser">
 
        <id name="id" type="string" unsaved-value="null">
            <column name="ID" sql-type="char(32)"/>
            <generator class="uuid.hex"/>
        </id>
 
        <discriminator column="DISCRIMINATOR_USERTYPE" type="string"/>
 
        <property name="name" type="string" not-null="true">
            <column name="NAME" length="16" not-null="true"/>
        </property>
 
        <property name="password" type="string" not-null="true">
            <column name="PASSWORD" length="16" not-null="true"/>
        </property>
 
        <subclass name="onlyfun.caterpillar.PowerUser" discriminator-value="POWER">
            <property name="level" type="integer" column="POWERUSER_LEVEL"/>
            <property name="otherOfPower" type="string" column="POWER_OTHER"/>
        </subclass>
      
        <subclass name="onlyfun.caterpillar.GuestUser" discriminator-value="GUEST">
            <property name="otherOfGuest" type="string" column="GUEST_OTHER"/>
        </subclass>
    </class>
 
</hibernate-mapping>

 在表格中,我们增加一个字段DISCRIMINATOR_USERTYPE来记录储存的类别是属于User、PowerUser或是 GuestUser的记录,如果该字段是ParentUser,则表示该笔数据是User类别,如果是POWER,表示是PowerUser的记录,如果是GUEST,表示是GuestUser的记录,在映像子类别时,使用<subclass>指明映像的子类别以及其 discriminator-value。
 我们可以在数据库中建立数据表格如下:
create table USER (
    ID char(32) not null,
    DISCRIMINATOR_USERTYPE varchar(255) not null,
    NAME varchar(16) not null,
    PASSWORD varchar(16) not null,
    POWERUSER_LEVEL integer,
    POWER_OTHER varchar(255),
    GUEST_OTHER varchar(255),
    primary key (ID)
);

 您可以将资料表的建立工作,透过SchemaExportTask来自动建立,您可以参考这篇介绍:
使用SchemaExportTask
 假设我们在程序中如下储存数据的话:
PowerUser pu = new PowerUser();
        pu.setName("caterpillar");
        pu.setPassword("123456");
        pu.setLevel(1);
        pu.setOtherOfPower("PowerUser's field");
 
        GuestUser gu = new GuestUser();
        gu.setName("momor");
        gu.setPassword("654321");
        gu.setOtherOfGuest("GuestUser's field");
 
        Session session = sessionFactory.openSession();
        Transaction tx= session.beginTransaction();    
        session.save(pu);
        session.save(gu);
      
        tx.commit();
        session.close();

 则资料表中将会有以下的内容(没有显示ID字段):
+------------------------+-------------+----------+-----------------+-------------------+-------------------+
| DISCRIMINATOR_USERTYPE | NAME        | PASSWORD | POWERUSER_LEVEL | POWER_OTHER       | GUEST_OTHER       |
+------------------------+-------------+----------+-----------------+-------------------+-------------------+
| POWER                  | caterpillar | 123456   |               1 | PowerUser's field | NULL              |
| GUEST                  | momor       | 654321   |            NULL | NULL              | GuestUser's field |
+------------------------+-------------+----------+-----------------+-------------------+-------------------+

 您可以观察实际的储存方式,注意DISCRIMINATOR_USERTYPE字段,它用以标示该列属于哪一个类别的数据,如果要查询数据的话,例如查询所有PowerUser的数据,我们只要如下进行:
Session session = sessionFactory.openSession();
    
        List users = session.find("from PowerUser");
        session.close();
        for (ListIterator iterator = users.listIterator(); iterator.hasNext(); ) {
            PowerUser user = (PowerUser) iterator.next();
            System.out.println(user.getName() +
                               "/n/tPassword: " + user.getPassword());
 
            System.out.println("/tPower: " + user.getOtherOfPower() +
                               "/n/tLevel: " + user.getLevel());
        }
 
 
 您可以观察Hibernate真正所执行的SQL的内容,看看where就知道它如何查询PowerUser的数据:
{code:borderStyle=solid}select poweruser0_.ID as ID,
             poweruser0_.POWERUSER_LEVEL as POWERUSE5_,
             poweruser0_.POWER_OTHER as POWER_OT6_,
             poweruser0_.NAME as NAME,
             poweruser0_.PASSWORD as PASSWORD
             from USER poweruser0_ where poweruser0_.DISCRIMINATOR_USERTYPE='POWER';

 使用session.find("from GuestUser");就可以查询GuestUser的数据,您也可以取回所有User型态的数据,例如:
Session session = sessionFactory.openSession();
    
        List users = session.find("from User");
        session.close();
 
        for (ListIterator iterator = users.listIterator(); iterator.hasNext(); ) {
            User user = (User) iterator.next();
            System.out.println(user.getName() +
                               "/n/tPassword: " + user.getPassword());
            if(user instanceof PowerUser)
                System.out.println("/tPower: " + ((PowerUser)user).getOtherOfPower() +
                                   "/n/tLevel: " + ((PowerUser)user).getLevel());
            else
                System.out.println("/tGuest: " + ((GuestUser)user).getOtherOfGuest());
        }

 Hibernate可以使用父类别来取得所有的子类别数据,我们知道所有的Java类别都继承自Object,所以如果您使用session.find("from java.lang.Object");,就将会取回数据库中所有表格的数据。
 有关于继承关系映射的第三种作法,将留待下一个主题说明。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值