首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 开源 FAQ 第二书店 博文视点 程序员
频道: 研发 数据库 中间件 信息化 视频 .NET Java 游戏 移动 服务: 人才 外包 培训
    图书品种:235680
       
热门搜索: ASP.NET Ajax Spring Hibernate Java

6.2  组件的集合

可以把Image映射为实体类,并创建一个从Item到Image的一对多关系。但是这没有必要,因为Image可以建模为一个值类型:这个类的实例有一个依赖的生命周期,不需要它们自己的同一性,并且不必支持共享的引用。

作为一个值类型,Image类定义了属性name、filename、sizeX和sizeY。它与它的所有者Item实体有着单个关联,如图6-5所示。

就如你可以从复合关联风格(图中黑色菱形处)中所见,Image是Item的一个组件,Item则是负责Image实例的生命周期的实体。关联的多样性进一步把这个关联声明为多值(many- valued)——也就是说,同一个Item实例有多个(或者0个)Image实例。

来快速看一下Java中的这个实现,以及XML格式的映射。

图6-5 Item中Image组件的集合

6.2.1  编写组件类

首先,把Image类实现为一般的POJO。如第4章所述,组件类没有标识符属性。你必须实现equals()(和hashCode()),并比较name、filename、sizeX和sizeY属性。Hibernate依赖这个等同性子程序检查实例中的修改。并非所有的组件类都需要equals()和hashCode()的定制实现(前面已经提到过这一点)。但是,我们建议把它用给任何组件类,因为这种实现很简单,并且“小心不出大错”可是至理名言啊。

Item类可以有图片的Set,不允许重复。我们来把这一思想映射到数据库。

6.2.2  映射集合

组件的集合被类似地映射到JDK值类型的集合。唯一的区别是用<composite-element>代替<element>标签。有序的图片集(内部使用LinkedHashSet)可以像这样映射:

图6-6展现了包含示例数据的表。

图6-6 组件映射的集合的示例数据表

这是一个集,因此集合表的主键是键列和所有元素列的一个复合:ITEM_ID、IMAGENAME、FILENAME、SIZEX和SIXEY。因为这些列都出现在主键中,需要用not-null="true"声明它们(或者确保它们在任何现有的Schema中都为NOT NULL)。复合主键中任何列都不可以为空——因为你无法辨别不知道的东西。这可能是这个特定映射的一个缺点。在改善这一点之前(可能你猜到了,用标识符bag),我们来启用双向导航。

6.2.3  启用双向导航

从Item到Image的关联是单向的。可以通过Item实例访问集合并迭代anItem.getImages(). iterator()导航到该图片。这是可以获得这些图片对象的唯一方法;没有其他的实体保存对它们(还是值类型)的引用。

另一方面,从一张图片导航回到一件货品没有意义。但是,有时候访问后退指针就像访问anImage.getItem()一样可能会比较方便。如果把<parent>元素添加到映射,Hibernate就会为你填入这个属性:

但是,真正的双向导航是不可能的。你无法单独获取一个Image,然后导航回到它的父Item。这是一个重要的问题:你可以通过查询它们来加载Image实例。但是当你在HQL中查询或者使用Criteria查询时,这些Image对象都没有引用它们的所有者(属性为null)。它们作为标量值(scalar value)获取。

最后,声明所有属性为not-null可能并不是你所希望的。如果任何属性列都是可为空的,IMAGE集合表就需要一个不同的主键。

6.2.4  避免非空列

类似于<idbag>提供的那个额外的代理标识符属性,现在代理键列要派上用场了。作为一种附带作用,<idset>也允许重复——明显与集的概念冲突。基于各种各样的原因(包括事实上也没有人曾经要过这一特性),Hibernate没有提供<idset>或者除了<idbag>之外的任何代理标识符集合。因而,要通过包语义把Java属性改为Collection:

这个集合现在也允许重复Image元素了——这是用户接口或者任何其他应用程序代码的责任,如果需要集语义,就要避免这些重复元素。映射添加了代理标识符列到集合表:

集合表的主键现在是ITEM_IMAGE_ID列,在Image类上实现equals()和hashCode()并不重要(至少Hibernate不需要)。你也不必用not-null="true"来声明属性。它们可以为空,如图6-7所示。

图6-7 使用带有代理键的包的Image组件的集合

应该指出,在这个包映射和标准的父/子实体关系(如本章前面映射过的那个)之间并没有太大的区别。表是一致的。这种选择主要是个人偏爱的问题。父/子关系支持对子实体和真正的双向导航的共享引用。为此付出的代价是更复杂的对象生命周期。值类型的实例可以通过添加新元素到集合而创建,并与持久化的Item关联。也可以通过从集合中移除元素来解除关联和永远删除它们。如果Image要成为一个支持共享引用的实体类,同样的操作在应用程序中就需要更多的代码,如稍后所见。

转换到不同主键的另一种方法是map。可以从Image类中移除name属性,并用图片名称作为map的键:

集合表的主键现在是ITEM_ID和IMAGENAME的复合。

像Image这样的复合元素类不是只限于像filename这样基本类型的简单属性。它可以包含其他的组件,通过<nested-composite-element>映射,甚至对实体的<many-to-one>关联。但是它无法拥有集合。包含多对一关联的复合元素很有用,第7章会回到这种映射的话题。

这样就结束了有关XML格式的基本集合映射的讨论。就像本节开头提到的,用注解映射值类型的集合,与以XML格式映射相比有所不同;在编写本书之时,它还不是Java Persistence标准的一部分,但是在Hibernate中它还是可用的。

查看所有评论(0)条】

最近评论



正在载入评论列表...
热点评论