如果应用程序中的对象有继承的关系,我们可以有三种策略将这种关系映像至数据表上。
最简单的方式就是给每个对象一个表格,如果父类别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./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");,就将会取回数据库中所有表格的数据。 有关于继承关系映射的第三种作法,将留待下一个主题说明。 |
|
来自: WindySky > 《Hibernate入门》