Hibernate和Spring是两个杰出的开源框架,它们在越来越多的J2EE应用中得到采用。尽管它们致力于解决的问题有很大区别,它们却都有一个重要特性:依赖注入。Spring有助于在将对象返回给客户端之前整理出对象之间的依赖关系,从而大大减少客户端的编码。而Hibernate则擅长于在将整个对象模型返回给客户端之前整理出数据模型所表现的依赖关系。当直接使用JDBC将数据模型映射为对象模型时,我们通常需要编写大量的代码以构建对象模型。而Hibernate消除了其中的大部分编码工作。
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:
- 需要formula的计算结果时。与元素discriminator、element、map-key、map-key-many-to-many和property一起使用formula属于这类情况。
- 为了连接的目的需要使用formula时。与元素many-to-one、one-to-one和many-to-many一起使用formula属于这类情况。
第一类:从formula获取计算结果 Discriminator(识别器) 在现实数据模式中,经常出现使用一个表来描述另一个表的情况。在对象关系映射中,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映射,如下:
<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/N |
ProductReleaseID |
SubProductAllowable |
... |
1 |
11 |
1 |
i |
2 |
601 |
0 |
i |
. ProductRelease表中的记录
S/N |
ProductID |
ProductReleaseID |
... |
1 |
10000001 |
11 |
i |
2 |
20000001 |
601 |
... |
表 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表检索货币名称。如您所见,这些直接的映射可以消除大量的转换编码。
map-key
formula允许map-key取任何可能的值。在下面的例子中(图3),我们希望Role_roleID成为
对象模型的map-key(图4)。
图3. 用户角色数据模式
图4. 用户角色对象模型
在上面的数据模式中,User和Role被通过一个称为User_has_Role的多对多的关系表连接起来。为了获取一个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"
class="Role"/>
</map>
</class>
<class name="Role">
<id name="roleID"/>
</class>
</hibernate-mapping>
Role_RoleID用作many-to-many元素的连接列值。然而,Hibernate不允许map-key和many-to-many的column属性同时使用Role_RoleID。但是使用一个formula,Role_RoleID还是可以用于map-key。
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),我们使用下面的映射:
<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表的一个独有的键。将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映射为:
<hibernate-mapping>
<class name="Company" table="Company" >
<id name="id" />
<one-to-one name="defaultContactPerson"
property-ref="defaultContactPerson" >
<formula>id</formula>
<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>
其他:many-to-many
formula可以与many-to-many元素一起用于从关系表到实体表的特殊连接,尽管通常不需要这样做。
结束语
本文中的例子展示了大部分的formula使用场景。当需要formula的计算值时,formula表达式将出现在产生的SQL语句的select部分。而当formula用于连接时,它出现在产生的SQL语句的where部分。此外,formula表达式可以使用任意的SQL非标准语言,只要目标数据库支持。因此,formula有助于无需编码地实现从数据模型到对象模型的细粒度映射。
参考资料
原文出处:Hibernate 3 Formulas http://www.onjava.com/pub/a/onjava/2005/08/03/hibernate.html
分享到:
相关推荐
2.4. Hibernate独有的注解扩展:除了标准的EJB3注解,Hibernate还提供了一些自定义注解,如`@GeneratedValue`用于设置主键生成策略,`@Formula`用于在属性中使用SQL表达式,`@Cache`用于配置缓存,`@Filter`用于动态...
5.1.20. 字段和规则元素(column and formula elements) 5.1.21. 引用(import) 5.1.22. any 5.2. Hibernate 的类型 5.2.1. 实体(Entities)和值(values) 5.2.2. 基本值类型 5.2.3. 自定义值类型 5.3. 多次...
- `@Entity`、`@Id`、`@Column`等是标准的JPA注解,而`@Formula`、`@Cacheable`、`@Filter`等是Hibernate特有的,提供更丰富的功能,如计算属性、缓存策略和动态过滤。 5. **通过XML覆写元数据** 虽然注解是首选...
此版本标志着Hibernate框架中的一个特定阶段,特别是关于如何利用注解(Annotations)来简化Java对象与数据库表之间的映射。 #### Hibernate Annotations 简介 Hibernate 是一款非常流行的 Java 持久化框架,它通过...
5.1.20. 字段和规则元素(column and formula elements) 5.1.21. 引用(import) 5.1.22. any 5.2. Hibernate 的类型 5.2.1. 实体(Entities)和值(values) 5.2.2. 基本值类型 5.2.3. 自定义值类型 5.3. 多次...
EJB3 注解是 Hibernate 用来标注实体Bean的一种标准方式,它允许开发者直接在实体Bean类上添加注解来定义映射规则。 - **2.2.1 声明实体Bean** - **2.2.1.1 定义表(Table)**:使用 `@Table` 注解来指定实体Bean所...
5.1.20. 字段和规则元素(column and formula elements) 5.1.21. 引用(import) 5.1.22. any 5.2. Hibernate 的类型 5.2.1. 实体(Entities)和值(values) 5.2.2. 基本值类型 5.2.3. 自定义值类型 5.3. 多次...
5.1.20. 字段和规则元素(column and formula elements) 5.1.21. 引用(import) 5.1.22. any 5.2. Hibernate 的类型 5.2.1. 实体(Entities)和值(values) 5.2.2. 基本值类型 5.2.3. 自定义值类型 5.3. 多次映射同一个...
5.1.19. 字段和规则元素(column and formula elements) 5.1.20. 引用(import) 5.1.21. any 5.2. Hibernate 的类型 5.2.1. 实体(Entities)和值(values) 5.2.2. 基本值类型 5.2.3. 自定义值类型 5.3. SQL中引号包围...
5.1.20. 字段和规则元素(column and formula elements) 5.1.21. 引用(import) 5.1.22. any 5.2. Hibernate 的类型 5.2.1. 实体(Entities)和值(values) 5.2.2. 基本值类型 5.2.3. 自定义值类型 5.3. 多次...
- **无注解之属性的默认值:** 如果没有显式使用注解,Hibernate会默认将类的属性映射到表中的列。 - **映射主键属性:** 主键映射通过`@Id`注解实现。 - **映射继承关系:** - **每个类一张表:** 每个子类对应...
实体Bean是Hibernate中非常重要的概念之一,用于表示数据库中的表,并通过注解来映射其字段与数据库表中的列。 ##### 3.1 简介 实体Bean是表示数据库表的对象形式,在Hibernate中通过注解进行配置,可以实现对象与...
在Java实体类中使用`@Formula`注解,通常会结合JPA或Hibernate等ORM框架。下面通过一个具体的例子来说明如何使用`@Formula`: ```java @Entity public class News { private int id; private String title; ...
- **1.1.7 加载并存储对象**:演示如何使用 Hibernate API 来加载数据库中的数据到 Java 对象,并将 Java 对象持久化到数据库。 ##### 1.2 第二部分 — 关联映射 此章节深入探讨了 Hibernate 中对象之间的关联映射...
在Hibernate 3.x版本后,注解方式逐渐成为其主要配置方法之一,它简化了开发流程,提高了开发效率。 #### 二、Hibernate注解基础 - **@Entity**:标记一个类为实体类,表示该类与数据库表相对应。 - **@Table**:...
5.1.19. 字段和规则元素(column and formula elements) 5.1.20. 引用(import) 5.1.21. any 5.2. Hibernate 的类型 5.2.1. 实体(Entities)和值(values) 5.2.2. 基本值类型 5.2.3. 自定义值类型 5.3. SQL中引号包围...
3. **映射关系**:Hibernate Annotations支持多种映射关系,包括一对多、多对一、一对一、多对多等。开发者可以使用@OneToMany、@ManyToOne、@OneToOne、@ManyToMany等注解来表示这些关系。 4. **属性映射**:注解...
详细的Hibernate3的帮助文档 前言 1. 翻译说明 2. 版权声明 1. 在Tomcat中快速上手 1.1. 开始Hibernate之旅 1.2. 第一个持久化类 1.3. 映射cat 1.4. 与Cat同乐 1.5. 结语 2. Hibernate入门 2.1. 前言 2.2. ...