[转]Hibernate 3 Formulas(翻译)
Hibernate 3 Formulas(翻译)
Hibernate 和 Spring 这两个突出的开源框架被越来越多的应用到 J2EE 中。尽管目标有着不同的问题空间,它们却共享一个关键特性:依赖注入。在对象返回到客户端之前 Spring 协助挑选出这些对象间依赖关系,减少客户端代码量。而 Hibernate 专门挑选出在完整的对象模型返回客户端之前由数据模型表现的依赖关系。当使用 JDBC 直接从数据模型映射到对象模型时,我们通常需要书写大量的代码来构建对象模型。Hibernate 的出现淘汰了这种繁琐的编码工作。
Hibernate 2.x 提供基本的表到对象的映射,标准关联映射(包括 one-to-one, one-to-many 以及 many-to-many 关系),多态映射,等等。Hibernate 3.x 沿着路线继续前进,formula、filter、subselect 等,使映射更加灵活,提供用细粒度的解释特性。
在本文中,将阐述 formula 到底有哪些特性可帮助我们进行模型转换。Hibernate 3.x 之前,formula 属性只能出现在 property 元素中。但是到了现在,你可以在许多元素中使用 Hibernate 3.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 参考相应的产品出厂记录,包括 product release name、type、release date 等等。
图 1. Product 和 product release
ProductRelease 表中有个有趣的属性 SubProductAllowable,该属性的值为 1 或 0。值为 1 代表允许任何的次品出厂,但是 0 不允许次品出厂。
图 2 展示了由数据模型解释的对象模型。Nested 接口定义了 getSubProducts 和 setSubProducts 方法。NestedProduct 类继承 Product 基类并实现 Nested 接口。无论产品数据记录是 Product 或 NestedProduct,都取决于产品出厂记录中 SubProductAllowable 的值。
图 2. Product 和产品出厂对象域模型
为了完成模型转换,我们使用如下的 Hibernate 3.x 映射:
<hibernate-mapping>
<class name="Product"
discriminator-value="0" lazy="false">
<id name="id" type="long"/>
<discriminator
formula="(select pr.SubProductAllowable
from ProductRelease pr
where pr.productReleaseID=
productReleaseID)"
type="integer" />
<subclass name="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 等等。
<property name="averagePrice" formula="(select avg(pc.price) from PriceCatalogue pc, SelectedItems si where si.priceRefID=pc.priceID)"/>
此外,formula 也能协助从基于当前记录的特定值向其它表检索数据。例如:
<property name="currencyName" formula="(select cur.name from currency cur where cur.id= currencyID)"/>
这将由助于从 currency 表检索 currency name。正如你所看到的,这样直接映射可消除许多转换编码。
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>
<class name="User">
<id name="userID"/>
<map name="roles"
table="UserRole"/>
<key column="User_userID"/>
<map-key
formula="Role_RoleID"
type="string"/>
<many-to-many
column="Role_RoleID"
/>
图 5. 用户角色数据 schema
图 6. 用户角色对象模型
为了说明对象模型(图 6)中默认联系人关系,我们使用如下映射文件:
<hibernate-mapping>
<class name="Company" table="Company">
<id name="id" />
<many-to-one
name="defaultContactPerson"
property-ref="defaultContactPerson">
<column name="id"/>
<formula>1</formula>
</many-to-one>
</class>
<class name="Person" >
<id name="id" />
<properties name="defaultContactPerson">
<property name="companyID" />
<property name="defaultFlag" />
</properties>
</class>
</hibernate-mapping>
如上,我们把 companyID 和 defaultFlag 组织到名为 defaultContactPerson 的 properties 元素中,做为 Person 表的 unique key。Company 类中的 many-to-one 元素连接 Person 表的 defaultContactPerson properties 元素。输出的 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 来映射:
<hibernate-mapping>
<class name="Company" table="Company" >
<id name="id" />
<one-to-one name="defaultContactPerson"
property-ref="defaultContactPerson" >
<formula>id</formula>
<formula>1</formula>
</one-to-one>
</class>
<class name="Person" >
<id name="id" />
<properties name="defaultContactPerson">
<property name="companyID" />
<property name="defaultFlag" />
</properties>
</class>
</hibernate-mapping>
many-to-many
formula 用于当 many-to-many 元素为关系表和实体表连接的特殊关系,尽管通常没有必要这样用。
总结
文章范例展示了大部分 formula 的适用情景。当需要 formula 评估值时,formula 表达式将出现在 产生的 SQL 语句的 select 部分。当 formula 用于连接时,它出现在产生的 SQL 语句的 where 部分。此外,formula 表达式可用于任何 SQL 方言,只要目标数据库支持。最后,formula 可协助完成从数据模型到对象模型的无代码细粒度映射。
请注意!引用、转贴本文应注明原译者:Rosen Jiang 以及出处:http://www.blogjava.net/rosen