映射继承关系

  继承关系是关系数据与面向对象数据结构之间的主要差异之一,hibernate中支持3种类型的继承形式:
1。表与子类之间的独立一对一关系
如 B和C 继承A,那么就有两张表分别对应B C,他们都含有A的内容

2。每个子类对应一张子表,并与主类共享主表
现在就要有三张表,为父类单独设立一张表,子表中只包含子类所扩展的属性,子表和父表通过外键相关联。

3。表与类的一对多关系
现在只要一张表,同时包含个子类,只是添加一个字段来区分不同的子类。

下面通过例子看一下这几种形式的做法。
图书大厦中既有书籍又有音像(如DVD),他们都是货物,但又有不同的属性,书籍有页数的属性,DVD有区域码的属性。我们将共性抽象为一个基类,子类体现具体特性。
如基类为Item(id, name), Book(page), DVD(regionCode)

1。表与子类之间的独立一对一关系

我们建两张表 book(id, name, pageCount), dvd(id, name, regionCode)
由于book,dvd由item继承而来,自然继承了item中的id,name属性,每个子类都分别对应一个独立的表,这张表中包含了子类所需的所有字段。

//book.hbm.xml
<class
 name="Book"
 table="book"
>
 <id
  name="Id"
  type="integer"
  column="id"
 >
  <generator class="native"/>
 </id>

 <property
  name="Name"
  column="name"
  type="string"
  not-null="true"
  length="45"
 />
 <property
  name="PageCount"
  column="pageCount"
  type="integer"
  not-null="true"
  length="10"
 />


</class>

//Dvd.hbm.xml
<class
 name="Dvd"
 table="dvd"
>
 <id
  name="Id"
  type="integer"
  column="id"
 >
  <generator class="native"/>
 </id>

 <property
  name="Name"
  column="name"
  type="string"
  not-null="true"
  length="45"
 />
 <property
  name="RegionCode"
  column="regionCode"
  type="string"
  not-null="true"
  length="45"
 />


</class>

可以看到,其映射方式与普通单表映射并没有什么不同,那么,Book 与 DVD是不是没有一点关系呢?

Book,Dvd继承了Item,这种关系在hibernate中以多态(polymorphism)进行描述,上面的配置文件的class节点中并没有出现polymorphism属性设定,这也意味着Book Dvd均采用了默认的隐式多态(polymorphism="implicit").

当我们执行HQL:“from Item"时,hibernate会自动在当前环境中查找所有polymorphism="implicit"的子类,返回子类对应的所有库表记录。

执行代码:
List list = (List)session.createQuery("from Item").list();
Iterator it = list.iterator();
while(it.hasNext()){
 Item item = (Item)it.next();
 System.out.println(item);
}

得到输出:
Hibernate: select dvd0_.id as id2_, dvd0_.name as name2_, dvd0_.regionCode as regionCode2_ from dvd dvd0_
Hibernate: select book0_.id as id1_, book0_.name as name1_, book0_.pageCount as pageCount1_ from book book0_

可以看到hibernate同时查询了book dvd

这种模式是最简单的映射方式,但也有很大的局限性,如果父类有变化就得改每个子类的表,如果有很多子类,这时只想根据名字查出id,就得查询所有子类表后汇总,可见性能低下。


2。每个子类对应一张子表,并与主类共享主表

将父类Item单独映射到一张主表,Book,Dvd分别单独设立一张子表,子表中只包含子类的扩展的属性,同时,子表和父表通过外键相关联。

映射关系如下:
<class
 name="Item"
 table="item"
>
 <meta attribute="sync-DAO">false</meta>
 <id
  name="Id"
  type="integer"
  column="id"
 >
  <generator class="native"/>
 </id>

 <property
  name="Name"
  column="name"
  type="string"
  not-null="true"
  length="45"
 />

 <joined-subclass name="Dvd" table="dvd">
  <key column="id"/>
  <property
   name="RegionCode"
   column="regioncode"
   type="string"
   not-null="true"
   length="45"
  />
 </joined-subclass>
 <joined-subclass name="Book" table="book">
  <key column="id"/>
  <property
   name="PageCount"
   column="pagecount"
   type="integer"
   not-null="true"
   length="10"
  />
 </joined-subclass>
</class>

我们并没有单独为Book,Dvd编写单独的映射文件,而是通过 joined-subclass 节点在父类映射文件中配置。

joined-subclass节点格式与class节点类似,且joined-subclass可以嵌套,也就是说还可以为子类再指定子类。

执行代码:
Book book = new Book();
book.setName("abc");
book.setPageCount(100);

Dvd dvd = new Dvd();
dvd.setName("dd");
dvd.setRegionCode("1111111");

session.save(dvd);
session.save(book);

输出:
Hibernate: insert into item (name) values (?)
Hibernate: insert into dvd (regioncode, id) values (?, ?)
Hibernate: insert into item (name) values (?)
Hibernate: insert into book (pagecount, id) values (?, ?)

执行查询代码:
List list = (List)session.createQuery("from Item").list();
Iterator it = list.iterator();
while(it.hasNext()){
 Item item = (Item)it.next();
 System.out.println(item);
}

输出:
Hibernate: select item0_.id as id1_, item0_.name as name1_, item0_1_.regioncode as regioncode2_, item0_2_.pagecount as pagecount3_,
case when item0_1_.id is not null then 1 when item0_2_.id is not null then 2 when item0_.id is not null then 0 end as clazz_ from item item0_ left outer join dvd item0_1_ on item0_.id=item0_1_.id left outer join book item0_2_ on item0_.id=item0_2_.id

这种模式带来了更加清晰的数据逻辑划分,但看以看到,多表操作带来的性能消耗也是比较大的。

3。表与类的一对多关系

我们来修改item表的结构,现在他不但包括了原来的id,name字段,同时也包含了dvd,book的regioncode,pagecount字段,不同的类型通过类型(categroy)字段来区分,不论是dvd还是book类都可以保存在这张表中。

//Item.hbm.xml
<class
 name="Item"
 table="item"
>
 <meta attribute="sync-DAO">false</meta>
 <id
  name="Id"
  type="integer"
  column="id"
 >
  <generator class="native"/>
 </id>
 
 <discriminator
  column="category"
  type="string"
 />

 <property
  name="Name"
  column="name"
  type="string"
  not-null="true"
  length="45"
 />

 <subclass name="Dvd" discriminator-value="1">
  <property
   name="RegionCode"
   column="regioncode"
   type="string"
  />
 </subclass>
 <subclass name="Book" discriminator-value="2">
  <property
   name="PageCount"
   column="pagecount"
   type="integer"
  />
 </subclass>
</class> 

其中:通过discriminator节点,我们声明了用作子类辨别标识的字段名,指定当辨别字段值为1时,对应子类为Dvd,为2时,对应的子类为Book。运行期hibernate在读取item表时,会根据指定的辨别标示进行判断。

执行代码:
List list = (List)session.createQuery("from Book").list();
Iterator it = list.iterator();
while(it.hasNext()){
 Book item = (Book)it.next();
 System.out.println(item);
}

list = (List)session.createQuery("from Dvd").list();
it = list.iterator();
while(it.hasNext()){
 Dvd item = (Dvd)it.next();
 System.out.println(item);

输出:
Hibernate: select book0_.id as id1_, book0_.name as name1_, book0_.pagecount as pagecount1_ from item book0_ where book0_.category='2'
Hibernate: select dvd0_.id as id1_, dvd0_.name as name1_, dvd0_.regioncode as regioncode1_ from item dvd0_ where dvd0_.category='1'

可以看到,hibernate已经根据配置自动进行了类型识别。

irini   2006-12-03 19:47:30 评论:0   阅读:204   引用:0

发表评论>>

署名发表(评论可管理,不必输入下面的姓名)

姓名:

主题:

内容: 最少15个,最长1000个字符

验证码: (如不清楚,请刷新)

Copyright@2008 powered by YuLog