首页 > 应用开发 > Java > Hibernate 3中的formula
Hibernate 2.x提供了基本的表格到对象的映射、常见的关联映射(包括一对一、一对多和多对多关联)、多态映射等等。Hibernate 3.x则通过使用formula、filter、subselect等提高映射灵活性,提供细粒度的解释特性,从而将其推进到一个新的级别。
在本文中,我们将展示有助于模型转换的各种formula特性。在Hibernate 3.x之前,formula属性只能够出现在property元素中。现在仍然可以这样做,但是Hibernate 3.x提供了一个formula属性或元素(两者在formula的用法方面实质上是等效的),可以在许多元素中使用,包括discriminator、 many-to-one、one-to-one、element、many-to-many、map-key、map-key-many-to-many 和property。这样就大大提高了对象关系映射的灵活性,从而支持对复杂数据模型的更为细粒度的解释。
基本上,有两种情况必须使用formula:
在图1展示的例子中,有两个表:Product和ProductRelease。每个产品记录有一个ProductReleaseID来引用它对应的产品版本记录,包括产品版本名称、类型、版本日期等。

图1. 产品和产品版本数据模型
在ProductRelease表中有一个值得注意的属性是SubProductAllowable,它的值可以是0或1。值为1意味着允许该 产品版本中的任何产品有子产品,而值为0则意味着不允许有子产品。例如,有些产品由多个子产品组成,而有些产品只有该产品本身。
图2展示了一个对该数据模型解释而成的对象模型。Nested接口定义了getSubProducts和setSubProducts方法。 NestedProduct类扩展了基类Product并实现了Nested接口。一个产品数据记录应该是Product还是NestedProduct 取决于相应产品版本记录的SubProductAllowable值。

图2. 产品和产品版本对象的域模型
为了完成这个模型转换,我们使用了Hibernate 3.x映射,如下:
discriminator-value="0" lazy="false">
formula="(select pr.SubProductAllowable
from ProductRelease pr
where pr.productReleaseID=
productReleaseID)"
type="integer" />
discriminator-value="1"/>
如果formula表达式计算结果为0,也就是不支持子产品,则对象将属于Product类。如果结果是1,对象将是一个 NestedProduct。在表1和表2中,对Product表中的第一个记录(ProductID=10000001)来说,初始化的类将是 NestedProduct,因为它引用一个SubProductAllowable=1的ProductRelease记录。对Product表中的第 二个记录(ProductID=20000001)来说,初始化的类将是Product,因为它引用一个SubProductAllowable=0的 ProductRelease记录。
| S/N | ProductReleaseID | SubProductAllowable | ... |
| 1 | 11 | 1 | i |
| 2 | 601 | 0 | i |
| S/N | ProductID | ProductReleaseID | ... |
| 1 | 10000001 | 11 | i |
| 2 | 20000001 | 601 | ... |
此外,formula还可以基于当前记录的特定属性值从另一个表检索值。例如:
它从currency表检索货币名称。如您所见,这些直接的映射可以消除大量的转换编码。
map-keyformula允许map-key取任何可能的值。在下面的例子中(图3),我们希望Role_roleID成为对象模型的map-key(图4)。
图3. 用户角色数据模式

图4. 用户角色对象模型
在上面的数据模式中,User和Role被通过一个称为User_has_Role的多对多的关系表连接起来。为了获取一个User以及分配给它的所有角色,我们使用下面的映射:
Role_RoleID用作many-to-many元素的连接列值。然而,Hibernate不允许map-key和many-to-many的 column属性同时使用Role_RoleID。但是使用一个formula,Role_RoleID还是可以用于map-key。
table="UserRole"/>
formula="Role_RoleID"
type="string"/>
column="Role_RoleID"
class="Role"/>
Formula和map-key-many-to-many的用法与map-key类似。然而,map-key-many-to-many通常用于三重关联,其中map键是被引用的对象自身,而不是一个被引用的属性。
然而,有些地方不支持formula。有些数据库(如Oracle 7)不支持嵌入的select语句(即,嵌入一个SQL语句的select部分中的selectSQL),也不支持用于计算结果的formula。因此,需要首先检查是否支持嵌入式的selectSQL语句。
因为由Hibernate映射生成的SQL将formula表达式作为其select目标的一部分,所以对所使用的数据库的非标准语言将有助于充分使用formula,尽管这可能会降低代码的可移植性。
第二类:将formula用于连接 many-to-one现实世界数据模型中的另一个常见场景是私有关系映射,它是指除基本的一对一、一对多和多对多关系之 外的映射。formula是针对这种私有关系管理所提供的元素之一。图5展示了一个例子,其中一个公司可以有多个联系人,但是他们之中只能有一个是默认的 联系人。一个公司有多个联系人是典型的一对多关系。但是,为了标识默认联系人,ContactPerson表使用了一个defaultFlag属性(1为 是,0为否)。
图5. 用户角色数据模式

图6. 用户角色对象模型
为了将默认联系人关系解释为对象模型(图6),我们使用下面的映射:
name="defaultContactPerson"
property-ref="defaultContactPerson">
1
我们将companyID和defaultFlag聚合到一个名为defaultContactPerson的properties元素中,形 成Person表的一个独有的键。将Company类中的many-to-one元素与Person类中的 defaultContactPersonproperties元素连接。产成的SQL将类似于:
select c.id, p.id from Company c, Person p where p.companyID=c.id and p.defaultFlag=1
one-to-one
在Hibernate中,one-to-one主要用于两个表共用相同的主键。而对于外键关联,通常使用many-to-one。但是,使用formula,one-to-one可以通过外键连接多个表。上面的many-to-one例子可以使用one-to-one映射为:
property-ref="defaultContactPerson" >
id
1
其他:many-to-many
formula可以与many-to-many元素一起用于从关系表到实体表的特殊连接,尽管通常不需要这样做。
结束语 本文中的例子展示了大部分的formula使用场景。当需要formula的计算值时,formula表达式将出现在产生的SQL语句的select部分。而当formula用于连接时,它出现在产生的SQL语句的where部分。此外,formula表达式可以使用任意的SQL非标准语言,只要目标数据库支持。因此,formula有助于无需编码地实现从数据模型到对象模型的细粒度映射。
参考资料
[@more@]来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/711001/viewspace-930916/ ,如需转载,请注明出处,否则将追究法律责任。