[转]Hibernate 3 Formulas(翻译)
Hibernate3Formulas(翻译)
Hibernate和Spring这两个突出的开源框架被越来越多的应用到J2EE中。尽管目标有着不同的问题空间,它们却共享一个关键特性:依赖注入。在对象返回到客户端之前Spring协助挑选出这些对象间依赖关系,减少客户端代码量。而Hibernate专门挑选出在完整的对象模型返回客户端之前由数据模型表现的依赖关系。当使用JDBC直接从数据模型映射到对象模型时,我们通常需要书写大量的代码来构建对象模型。Hibernate的出现淘汰了这种繁琐的编码工作。
Hibernate2.x提供基本的表到对象的映射,标准关联映射(包括one-to-one,one-to-many以及many-to-many关系),多态映射,等等。Hibernate3.x沿着路线继续前进,formula、filter、subselect等,使映射更加灵活,提供用细粒度的解释特性。
在本文中,将阐述formula到底有哪些特性可帮助我们进行模型转换。Hibernate3.x之前,formula属性只能出现在property元素中。但是到了现在,你可以在许多元素中使用Hibernate3.x提供的formula属性或元素(formula用法方面都是一样的),包括discriminator、element、many-to-many、map-key、map-key-many-to-many、以及property。它增加了OR映射的灵活性,因此允许对复杂数据模型更加细粒的解释。
下面有两个formula应用场景:
1.formula用于评估结果的场合。在discriminator、element、map-key、map-key-many-to-many以及property元素中注入formula。
2.formula用于连接目的的场合。在many-to-one、one-to-one以及many-to-many元素中注入formula。
范畴1:从formula获得评估结果
Discriminator
在真实的数据schema中,经常出现一个表被用于描述其他表的情况。formula可协助提供灵活的多态OR映射。
在图1的范例中,有两个表:Product和ProductRelease。每条product记录都有一个ProductReleaseID参考相应的产品出厂记录,包括productreleasename、type、releasedate等等。
图1.Product和productrelease
ProductRelease表中有个有趣的属性SubProductAllowable,该属性的值为1或0。值为1代表允许任何的次品出厂,但是0不允许次品出厂。
图2展示了由数据模型解释的对象模型。Nested接口定义了getSubProducts和setSubProducts方法。NestedProduct类继承Product基类并实现Nested接口。无论产品数据记录是Product或NestedProduct,都取决于产品出厂记录中SubProductAllowable的值。
图2.Product和产品出厂对象域模型
为了完成模型转换,我们使用如下的Hibernate3.x映射:
<hibernate-mapping>
<classname="Product"
discriminator-value="0"lazy="false">
<idname="id"type="long"/>
<discriminator
formula="(selectpr.SubProductAllowable
fromProductReleasepr
wherepr.productReleaseID=
productReleaseID)"
type="integer"/>
<subclassname="NestedProduct"
discriminator-value="1"/>
</class>
</hibernate-mapping>
如果formula表达式评估结果为0时--也就是不允许次品出厂--那么对象将是Product类。如果结果是1,那么对象将是NestedProduct。在表1和2中,表Product的第一条记录(ProductID=10000001),已初始化的类将是NestedProduct,因为它参考一条SubProductAllowable=1的ProductRelease记录。表Product的第二条记录(ProductID=20000001),已初始化的类将是Product,因为它参考一条SubProductAllowable=0的ProductRelease记录。
S/NProductReleaseIDSubProductAllowable...
1111¡
26010¡表1.ProductRelease表中的记录
S/NProductIDProductReleaseID...
11000000111¡
220000001601...表2.Product表中的记录
Property
在property元素中的formula允许对象属性包含特定引伸值,比如对结果进行sum、average、max等等。
<propertyname="averagePrice"formula="(selectavg(pc.price)fromPriceCataloguepc,SelectedItemssiwheresi.priceRefID=pc.priceID)"/>
此外,formula也能协助从基于当前记录的特定值向其它表检索数据。例如:
<propertyname="currencyName"formula="(selectcur.namefromcurrencycurwherecur.id=currencyID)"/>
这将由助于从currency表检索currencyname。正如你所看到的,这样直接映射可消除许多转换编码。
map-key
formula允许map-key持有任何可能的值。下列范例(图3),我们想让Role_roleID成为对象模型的map-key(图4)。
图3.用户角色数据schema
图4.用户角色对象模型
在前面的数据schema中,User和Role由User_has_Role通过many-to-many关系关联调用。为了获取某个User所有的指派角色,我们进行如下映射:
<hibernate-mapping>
<classname="User">
<idname="userID"/>
<mapname="roles"
table="UserRole"/>
<keycolumn="User_userID"/>
<map-key
formula="Role_RoleID"
type="string"/>
<many-to-many
column="Role_RoleID"
class="Role"/>
</map>
</class>
<classname="Role">
<idname="roleID"/>
</class>
</hibernate-mapping>
Role_RoleID通常用于连接many-to-many元素的栏位值。Hibernate通常不允许Role_RoleID出现在map-key和many-to-many的栏位属性中。但是有了formula,Role_RoleID也能用于map-key。
element、map-key-many-to-many以及其他
element和property类似,能从任何有效的formula表达式赋予评估值。
map-key-many-to-many中formula的用法类似于map-key。但是,map-key-many-to-many通常用于三重关系,mapkey是一个被自己参考的对象,而不是被参考的属性。
那么,到底哪些情况下formula不支持呢?有些数据库(例如Oracle7)就不支持嵌入式select语句(也就是说一条selectSQL内嵌在另外一条selectSQL语句中),这种情况formula就不支持评估结果。因此,你应该首先检查嵌入式selectSQL语句是否被支持。
一旦Hibernate的映射拿formula表达式作为selectSQL选取的一部分,请确认数据库SQL方言是否允许使用formula,尽管这样将降低代码轻便性。
范畴2:formula用于连接
many-to-one
另一个普遍的场景是真实世界的数据模型是所有者关系映射,这意味着映射是不同于one-to-one、one-to-many以及many-to-many关系的,formula是提供所有者关系管理元素中的一个。图5展示了某公司可有多个联系人,但是其中只有一个为默认联系人的范例。一个公司有多个联系人是典型的one-to-many关系。但是,为了标识默认联系人,ContactPerson表使用了defaultFlag参数(1是yes,0是no)。
图5.用户角色数据schema
图6.用户角色对象模型
为了说明对象模型(图6)中默认联系人关系,我们使用如下映射文件:
<hibernate-mapping>
<classname="Company"table="Company">
<idname="id"/>
<many-to-one
name="defaultContactPerson"
property-ref="defaultContactPerson">
<columnname="id"/>
<formula>1</formula>
</many-to-one>
</class>
<classname="Person">
<idname="id"/>
<propertiesname="defaultContactPerson">
<propertyname="companyID"/>
<propertyname="defaultFlag"/>
</properties>
</class>
</hibernate-mapping>
如上,我们把companyID和defaultFlag组织到名为defaultContactPerson的properties元素中,做为Person表的uniquekey。Company类中的many-to-one元素连接Person表的defaultContactPersonproperties元素。输出的SQL像这样:
selectc.id,p.idfromCompanyc,Personpwherep.companyID=c.idandp.defaultFlag=1
one-to-one
Hibernate中,one-to-one主要用于两张表共享同一主键的情况。对于外键关联,我们通常使用many-to-one来代替。但是,有了formula,one-to-one可以通过外键连接表。上面的many-to-one范例可以通过one-to-one来映射:
<hibernate-mapping>
<classname="Company"table="Company">
<idname="id"/>
<one-to-onename="defaultContactPerson"
property-ref="defaultContactPerson">
<formula>id</formula>
<formula>1</formula>
</one-to-one>
</class>
<classname="Person">
<idname="id"/>
<propertiesname="defaultContactPerson">
<propertyname="companyID"/>
<propertyname="defaultFlag"/>
</properties>
</class>
</hibernate-mapping>
many-to-many
formula用于当many-to-many元素为关系表和实体表连接的特殊关系,尽管通常没有必要这样用。
总结
文章范例展示了大部分formula的适用情景。当需要formula评估值时,formula表达式将出现在产生的SQL语句的select部分。当formula用于连接时,它出现在产生的SQL语句的where部分。此外,formula表达式可用于任何SQL方言,只要目标数据库支持。最后,formula可协助完成从数据模型到对象模型的无代码细粒度映射。
请注意!引用、转贴本文应注明原译者:RosenJiang以及出处:http://www.blogjava.net/rosen