热门文章 | 热门软件| 热门源码 | 热门电影 | 知识库 | 联系我们
软件 源码 教程 影视 健康 招聘
  HTML | JavaScript | ASP | PHP | JSP | NET | VB | VC | VF | Windows | Linux | Mysql | Mssql | Oracle | Struts 
当前位置: 创世纪计算机资源网 -> 文章频道 ->hibernate 
站内搜索:
hibernate之集合类(Collections)映射(3)
作者:hibernate 来源:hibernate.org 整理日期:2007-3-6

一个拥有自己表的实体集合对应于多对多(many-to-many)关联关系概念。多对多关联是针对Java集合的最自然映射关联关系,但通常并不是最好的关系模型。

<many-to-many
        column="column_name"                               (1)
        class="ClassName"                                  (2)
        outer-join="true|false|auto"                       (3)
/>
(1) column(必需): 这个元素的外键关键字段名
 
(2) class (必需): 关联类的名称
 
(3) outer-join (可选 - 默认为auto): 在Hibernate系统参数中hibernate.use_outer_join被打开的情况下,该参数用来允许使用outer join来载入此集合的数据。 
 

例子:首先, 一组字符串:

<set name="names" table="NAMES">
    <key column="GROUPID"/>
    <element column="NAME" type="string"/>
</set>
包含一组整数的bag(还设置了order-by参数指定了迭代的顺序):

<bag name="sizes" table="SIZES" order-by="SIZE ASC">
    <key column="OWNER"/>
    <element column="SIZE" type="integer"/>
</bag>
一个实体数组,在这个案例中是一个多对多的关联(注意这里的实体是自动管理生命周期的对象(lifecycle objects),cascade="all"):

<array name="foos" table="BAR_FOOS" cascade="all">
    <key column="BAR_ID"/>
    <index column="I"/>
    <many-to-many column="FOO_ID" class="org.hibernate.Foo"/>
</array>
一个map,通过字符串的索引来指明日期:

<map name="holidays" table="holidays" schema="dbo" order-by="hol_name asc">
    <key column="id"/>
    <index column="hol_name" type="string"/>
    <element column="hol_date" type="date"/>
</map>
一个组件的列表:(下一章讨论)

<list name="carComponents" table="car_components">
    <key column="car_id"/>
    <index column="posn"/>
    <composite-element class="org.hibernate.car.CarComponent">
            <property name="price" type="float"/>
            <property name="type" type="org.hibernate.car.ComponentType"/>
            <property name="serialNumber" column="serial_no" type="string"/>
    </composite-element>
</list>
6.4. 一对多关联(One-To-Many Associations)
一对多关联直接连接两个类对应的表,而没有中间集合表。(这实现了一个一对多的关系模型)(译者注:这有别与多对多的关联需要一张中间表)。 这个关系模型失去了一些Java集合的语义:

map,set或list中不能包含null值

一个被包含的实体的实例只能被包含在一个集合的实例中

一个被包含的实体的实例只能对应于集合索引的一个值中

一个从Foo到Bar的关联需要额外的关键字字段,可能还有一个索引字段指向这个被包含的实体类,Bar所对应的表。这些字段在映射时使用前面提到的<key>和<index>元素。

<one-to-many>标记指明了一个一对多的关联。

<one-to-many class="ClassName"/>
(1) class(必须):被关联类的名称。 
 

例子

<set name="bars">
    <key column="foo_id"/>
    <one-to-many class="org.hibernate.Bar"/>
</set>
注意:<one-to-many>元素不需要定义任何字段。 也不需要指定表名。

重要提示:如果一对多关联中的<key>字段定义成NOT NULL,那么当创建和更新关联关系时Hibernate可能引起约束违例。为了预防这个问题,你必须使用双向关联,并且在“多”这一端(Set或者是bag)指明inverse="true"。参阅本章后面关于双向关联的讨论。

6.5. 延迟初始化(延迟加载)(Lazy Initialization)
(译者注: 本翻译稿中,对Lazy Initiazation和Eager fetch中的lazy,eager采取意译的方式,分别翻译为延迟初始化和预先抓取。lazt initiazation就是指直到第一次调用时才加载。)

集合(不包括数组)是可以延迟初始化的,意思是仅仅当应用程序需要访问时,才载入他们的值。对于使用者来说,初始化是透明的, 因此应用程序通常不需要关心这个(事实上,透明的延迟加载也就是为什么Hibernate需要自己的集合实现的主要原因)。但是, 如何应用程序试图执行以下程序:

s = sessions.openSession();
User u = (User) s.find("from User u where u.name=?", userName, Hibernate.STRING).get(0);
Map permissions = u.getPermissions();
s.connection().commit();
s.close();

Integer accessLevel = (Integer) permissions.get("accounts");  // Error!
这个错误可能令你感到意外。因为在这个Session被提交(commit)之前, permissions没有被初始化,那么这个集合将永远不能载入他的数据了。 解决方法是把读取集合数据的语句提到Session被提交之前。(然而,还有一种更先进的方法来解决这个问题。)

另外一种选择是不使用延迟初始化集合。既然延迟初始化可能引起上面这样错误,默认是不使用延迟初始化的。但是, 为了效率的原因, 们希望对绝大多数集合(特别是实体集合)使用延迟初始化。

延迟初始化集合时发生的例外被封装在LazyInitializationException中。

使用可选的 lazy 属性来定义延迟初始化集合:

<set name="names" table="NAMES" lazy="true">
    <key column="group_id"/>
    <element column="NAME" type="string"/>
</set>
在一些应用程序的体系结构中,特别是使用hibernate访问数据的结构, 代码可能会用在不用的应用层中, 可能没有办法保证当一个集合在初始化的时候, session仍然打开着。 这里有两个基本方法来解决这个问题:

在基于Web的应用程序中, 一个servlet过滤器可以用来在用户请求的完成之前来关闭Session。当然,这个地方(关闭session)严重依赖于你的应用程序结构中例外处理的正确性。在请求返回给用户之前关闭Session和结束事务是非常重要的,即使是在构建视图(译者注: 返回给用户的HTML页面)的时候发生了例外,也必须确保这一点。考虑到这一点,servlet过滤器可以保证能够操作这个Session。们推荐使用一个ThreadLocal变量来保存当前的Session。(参阅第一章,第 1.4 节 “与猫同乐”,有一个参考实现。)

在一个有单独的商业层的应用程序中, 商业逻辑必须在返回之前“准备好”Web层所需要的所有集合。这就是说商业逻辑层应该装载好所有的数据,把一个用例所需要的所有数据都初始化好,传递给表现/web层。通常, 应用程序为每个Web层需要的集合调用Hibernate.initialize()(必须在Session被关闭之前调用)或者通过使用Hibernate 查询,用FETCH子句来明确获取到整个集合。

You may also attach a previously loaded object to a new Session with update() or lock() before accessing unitialized collections (or other proxies). Hibernate can not do this automatically, as it would introduce ad hoc transaction semantics! 你也可以把先前装载的对象附加到一个新的Session去,需要在访问未初始化的集合类(或其他代理)前使用update() 或 lock()。Hibernate不能自动做这件事,这回带来特别的事务语义!

你可以使用Hibernate Session API中的filter() 方法来在初始化之前得到集合的大小:

( (Integer) s.filter( collection, "select count(*)" ).get(0) ).intValue()
filter() 或者 createFilter()同样被用于有效的重新载入一个集合的子集而不需要载入整个集合。

6.6. 集合排序(Sorted Collections)
Hibernate支持实现java.util.SortedMap和java.util.SortedSet的集合。你必须在映射文件中指定一个比较器:

[1]  [2]  [3]  [4]  [5]  
相关文章
暂无