<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping>
<class name="com.oreilly.hh.Album" table="ALBUM">
<meta attribute="class-description">
Represents an album in the music database, an organized list of tracks.
@author Jim Elliott (with help from Hibernate)
</meta>
<id name="id" type="int" column="ALBUM_ID">
<meta attribute="scope-set">protected</meta>
<generator class="native"/>
</id>
<property name="title" type="string">
<meta attribute="use-in-tostring">true</meta>
<column name="TITLE" not-null="true" index="ALBUM_TITLE"/>
</property>
<property name="numDiscs" type="integer" not-null="true"/>
<set name="artists" table="ALBUM_ARTISTS">
<key column="ALBUM_ID"/>
<many-to-many class="com.oreilly.hh.Artist" column="ARTIST_ID"/>
</set>
<set name="comments" table="ALBUM_COMMENTS">
<key column="ALBUM_ID"/>
<element column="COMMENT" type="string"/>
</set>
<list name="tracks" table="ALBUM_TRACKS" cascade="all">
<meta attribute="use-in-tostring">true</meta>
<key column="ALBUM_ID"/>
<index column="POS"/>
<composite-element class="com.oreilly.hh.AlbumTrack">
<many-to-one name="track" class="com.oreilly.hh.Track" cascade="all">
<meta attribute="use-in-tostring">true</meta>
<column name="TRACK_ID"/>
</many-to-one>
<property name="disc" type="integer" not-null="true"/>
<property name="positionOnDisc" type="integer" not-null="true"/>
</composite-element>
</list>
<property name="added" type="date">
<meta attribute="field-description">When the album was created</meta>
</property>
</class>
</hibernate-mapping>
The cascade attribute tells Hibernate that you want operations performed on a 'parent' object to be transitively applied to its 'child' or 'dependent' objects. It's applicable to all forms of collections and associations. There are several possible values to choose among. The most common are none (the default), save-update, delete, and all (which combines save-update and delete). You can also change the default from none to save-update throughout your entire mapping document by supplying a default-cascade attribute in the hibernate-mapping tag itself.
级联(cascade)属性告诉hibernate:所有对父对象的操作都将付诸于子对象和依赖对象上。级联可以应用于各种形式的集合和关联中。这里级联的具体取值可以有多个,最常用的有:none(默认值),save-update,delete和all(其中包含了save-update和delete)。你可以在hibernate-mappiong tag中通过设置default-casade属性,修改这里的casade的默认值,例如修改其默认值为save-update。
In our example, we want the tracks owned by an album to be automatically managed by the album, so that when we delete the album, its tracks are deleted. Note that we need to apply the cascade attribute both to the tracks collection and its constituent track element to achieve this. Also, by using a cascade value of all, we eliminate the need to explicitly save any Track objects we create for the album—the addAlbumTrack() method of Example 5-7 no longer needs the line:
session.save(track);
在我们的例子中,我们希望track完全由album自动掌管,当我们删除album时,它的track也会被删除。注意,这里我们需要在两处设置casade属性实现此任务:tracks集合和它的组成元素track。同样,由于我们讲casade设置为all,那么不再需要显式的保存为album创建的track对象,5-7例子中的addAlbumTrack方法不再需要调用session.save(track)方法。
By telling Hibernate that it's fully responsible for the relationship between an album and its track, we enable it to persist tracks when they're added to the album as well as delete them when the album itself is deleted.
通过高知hibernate,由其完全负责album和track直接的关系,可以保证track在加入到album时自动保存,在album删除时自动删除。
Delegating this sort of bookkeeping to the mapping layer can be very convenient, freeing you to focus on more abstract and important tasks, so it is worth using when appropriate. It's reminiscent of the liberation provided by Java's pervasive garbage collection, but it can't be as comprehensive because there is no definitive way to know when you're finished with persistent data by performing reachability analysis; you need to indicate it by calling delete() and establishing lifecycle connections. The trade-off between flexibility and simple automation is yours to make, based on the nature of your data and the needs of your project.
将这样的任务完全交代给持久层使得我们的任务更加的简便,可以让我们将注意力投注于更抽象更重要的业务,因此恰当的使用casade是值得的,这就像java的垃圾收集一样,使我们的工作得到了一定的解放。但是,由于目前并没有任何的可达性分析方法,可以确切的知道“你是否已经不再需要此持久层数据”,因此你必须调用delete()方法,才能建立起此生命周期链接。你必须依据你的数据的特点和项目的需要,在灵活性和自动化的简单性进行权衡。
For example, if you use Collections methods to remove a Track from an Album's tracks property, this breaks the link between the Album and Track but does not actually delete the Track record. Even if you later delete the entire Album, this Track will remain, because it wasn't linked to the Album at the time that it was deleted.
例如:如果你使用Album的tracks collection的remove方法,删除一个track,这将会移除album和track直接的链接,但是它并没真正的删除track记录。即使你后来整个的删除album,这个track也将会继续保留着,因为此时该track已经和album失去了链接。
//( 译者注)这里的含义是:级联是有范围的,表ALBUM和表TRACK之间通过表Album_Tracks建立了联系。在albu.hbm.xml中,进行了级联配置,使得Album和ALBUM_TRACKS之间级联。当删除某个album时,那么相应的ALBUM_TRACKS中的记录也将删除。如果对album中的tracks执行remove方法时,那么ALBUM_TRACKS中的相应记录也将删除。但是这里的级联却无法延伸到表TRACK中,TRACK表中的记录将安然无恙,依然存在。
//原文中的tracks出现在两处,一个是Album对象的属性,其对应着ALBUM_TRACKS的记录。一个则是单独的TRACK表,所以表述十分容易引起混淆。