返回介绍

另一种方法

发布于 2025-04-21 21:42:13 字数 3489 浏览 0 评论 0 收藏

这个试验表明标注确实是一种映射模型类的可行方法。通过为数不多的几步,我们就可以精确地维护前面章节中逐步建立的数据库模式,只是标注这种方法不能让我们在创建 Album 时级联创建 Track 对象。如果以稍微不同的方式来考虑 AlbumTrack 类,则还有另一种方法,让我们在数据库模式中能够维护这种自动的级联处理,同时也提供了一些其他功能。

将 AlbumTrack 映射为一个完整的实体,我们就可以添加级联标注,Hibernate 就会优先处理 Album 定义,以嵌入对 Track 的引用。这也给我们带来一些新的需要考虑的复杂问题,但其中一部分需要视不同的时机而定夺。首先,将 AlbumTrack 作为实体就需要具有 ID。同时,因为我们接着需要不从 Album 开始就可以处理 AlbumTrack 对象,所以应该扩充 AlbumTrack 模型,以提供从 ALBUM_TRACKS 表返回到 ALBUM 表的链接(我们将它用于 Hibernate 复合键)。为此,需要增加一个 album 属性。例 7-12 演示了 AlbumTrack 映射中关键的一部分,也是这种方法的独特之处所在。

例 7-12:将 AlbumTrack 类标注为实体

package com.oreilly.hh.data;

import java.io.Serializable;

import javax.persistence.*;

@Entity❶

@Table(name="ALBUM_TRACKS")

public class AlbumTrack{

@Id❷

@GeneratedValue(strategy=GenerationType.AUTO)

private Integer id;

@ManyToOne

@JoinColumn(name="ALBUM_ID",insertable=false, updatable=false,❸

nullable=false)

private Album album;

@ManyToOne(cascade=CascadeType.ALL)❹

@JoinColumn(name="TRACK_ID",nullable=false)

private Track track;

……

public Integer getId(){

return id;

}

public void setId(Integer id){

this.id=id;

}

public Album getAlbum(){

return album;

}

public Track getTrack(){

……

}

❶明显地,我们将类标注由 @Embeddable 修改为 @Entity,而且就在这里选择了表名,而不是在 Album 类的源文件中。

❷此处与基于 XML 的例子中的模式差别最大。以前我们的 ALBUM_TRACK 表使用一个复合主键,利用的是 ALBUM_ID 和 TRACK_ID 的一个特定组合在数据库中只有一个记录这一事实,这样就节省了我们在 ALBUM_TRACK 表中提供一个单独的 ID 列的需要。

虽然让 AlbumTrack 成为一个实体后还保留原来的数据库模式也是可能的,不过这需要付出不少的努力。JPA 要求所有的复合主键都要被映射为一个单独的类,由这个类来提供一个主键的各个成员。所以,为了保留原来我们的数据库模式,就必须对模型类进行比较大的修改,只是为了持有 AlbumTrack 类的主键而创建一个新的类。

相反,也可以稍微修改一下数据库模式,为 ALBUM_TRACKS 增加一个 ID 列(应该承认,这个列没有什么实际用途),看起来是一种破坏力比较小的选择。无论如何,当改变映射方法时,我们将要面对各种权衡,这个例子就是一个有趣的演示。

❸到 Album 的映射是我们以前见过的 @ManyToOne,但是还需要提供一些额外的参数,才能让它按我们想要的方式来工作。这段“咒语”用于重新创建我们曾经用 Album.hbm.xml 取得的映射效果,让 Hibernate 完全控制对 ALBUM_TRACKS 表的 ALBUM_ID 列的维护。如果没有 @JoinColumn 标注中的 insertable 和 updatable 属性,我们就得必须修改 AlbumTest,为每个 AlbumTrack 对象显式地设置 album 属性,这样也就意味着失去了一些我们想要从 Hibernate 得到的自动处理。

当使用实体上的索引映射时(具有 @IndexColumn 或 @MapKey),你应该记住这种应用模式。

❹既然 AlbumTrack 是一个实体,Hibernate 就能够为它的 track 属性应用 cascade 的设置。

❺我们可以强化一个概念,Hibernate 在管理到专辑的链接(album 属性)时,并没有使用 setAlbum()方法。

当然,在 Album.java 中这一关系的映射方式也会有稍微的不同,如例 7-13 所示。

例 7-13:Album.java 中的 AlbumTracks 实体映射

……

@OneToMany(cascade=CascadeType.ALL)

@IndexColumn(name="LIST_POS")

@JoinColumn(name="ALBUM_ID",nullable=false)

private List<AlbumTrack>tracks;

……

@OneToMany 标注中的级联(cascade)设置,它通过 Album 中嵌入的 Track 引用来建立这种完整的级联关系,我们在例 5-13 开发的 Album.hbm.xml 最终版本中也曾经建立过这样的关联,在那个例子中是由专辑对象来管理它们的曲目对象的生命周期。在这里,需要再一次将 AlbumTest 的 addAlbumTrack()方法中用于保存曲目的那行代码注释掉。这样,我们用不同的数据库模式重新创建了原来的功能。如果不怕麻烦,也可以创建一个类来负责管理复合键,这样就可以保留原来的功能和数据库模式。

和许多其他 Hibernate API(以及一般的面向对象的建模方法)一样,可以用多种方法来实现一个功能。

现在怎么办

希望这一章可以让你对如何用标注来表达数据映射有个大致的了解,也希望当你为自己的项目探索新的选择时,本章介绍的内容可以作为一个良好的起点。在本书接下来的部分,我们将不列举相关技术的所有细节和功能(这应该是 Hibernate 参考手册的任务),虽然有时介绍的比较肤浅,但希望我们讨论的一些问题可以作为帮助你解决模糊问题的示例。如果所有办法都解决不了问题,那只能尝试让问题重新出现,再将错误消息粘贴到 Google 上搜索!或者,如果你是好“公民”的话,可以研究一下源代码,将问题发布到 Hibernate 论坛上以寻求帮助,把解决问题的希望留给未来的用户,并帮助突出应该加强 Hibernate 文档的哪些部分。

在接下来的几章中,我们将继续回到基于 XML 的世界,看看几种查询数据的方法。但是,还应该记住标注的概念,在本书结尾部分介绍 Spring 和 Stripes 的章节中,将会再次用到它们。

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。