任何值集合或者多对多关联需要专用的具有一个或多个外键字段的collection table、一个或多个collection element column,以及还可能有一个或多个索引字段。
用于映射集合类的Hibernate映射元素取决于接口的类型。比如, <set>
元素用来映射Set
类型的属性。
<class name="Product"> <id name="serialNumber" column="productSerialNumber"/> <set name="parts"> <key column="productSerialNumber" not-null="true"/> <one-to-many class="Part"/> </set> </class>
除了<set>
,还有<list>
, <map>
, <bag>
, <array>
和 <primitive-array>
映射元素。<map>
具有代表性:
<map name="propertyName" (1) table="table_name" (2) schema="schema_name" (3) lazy="true|extra|false" (4) inverse="true|false" (5) cascade="all|none|save-update|delete|all-delete-orphan|delet(6)e-orphan" sort="unsorted|natural|comparatorClass" (7) order-by="column_name asc|desc" (8) where="arbitrary sql where condition" (9) fetch="join|select|subselect" (10) batch-size="N" (11) access="field|property|ClassName" (12) optimistic-lock="true|false" (13) mutable="true|false" (14) node="element-name|." embed-xml="true|false" > <key .... /> <map-key .... /> <element .... /> </map>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
集合实例在数据库中依靠持有集合的实体的外键加以辨别。此外键作为集合关键字段(collection key column)(或多个字段)加以引用。集合关键字段通过<key>
元素映射。
在外键字段上可能具有非空约束。对于大多数集合来说,这是隐含的。对单向一对多关联来说,外键字段默认是可以为空的,因此你可能需要指明 not-null="true"
。
<key column="productSerialNumber" not-null="true"/>
外键约束可以使用ON DELETE CASCADE
。
<key column="productSerialNumber" on-delete="cascade"/>
对<key>
元素的完整定义,请参阅前面的章节。
集合几乎可以包含任何其他的Hibernate类型,包括所有的基本类型、自定义类型、组件,当然还有对其他实体的引用。存在一个重要的区别:位于集合中的对象可能是根据“值”语义来操作(其声明周期完全依赖于集合持有者),或者它可能是指向另一个实体的引用,具有其自己的生命周期。在后者的情况下,被作为集合持有的状态考虑的,只有两个对象之间的“连接”。
被包容的类型被称为集合元素类型(collection element type)。集合元素通过<element>
或<composite-element>
映射,或在其是实体引用的时候,通过<one-to-many>
或<many-to-many>
映射。前两种用于使用值语义映射元素,后两种用于映射实体关联。
所有的集合映射,除了set和bag语义的以外,都需要指定一个集合表的索引字段(index column)——用于对应到数组索引,或者List
的索引,或者Map
的关键字。通过<map-key>
,Map
的索引可以是任何基础类型;若通过<map-key-many-to-many>
,它也可以是一个实体引用;若通过<composite-map-key>
,它还可以是一个组合类型。数组或列表的索引必须是integer
类型,并且使用 <list-index>
元素定义映射。被映射的字段包含有顺序排列的整数(默认从0开始)。
<list-index
column="column_name" (1)
base="0|1|..."/>
|
|
|
|
<map-key column="column_name" (1) formula="any SQL expression" (2) type="type_name" (3) node="@attribute-name" length="N"/>
|
|
|
|
|
|
<map-key-many-to-many column="column_name" (1) formula="any SQL expression" (2)(3) class="ClassName" />
|
|
|
|
|
|
值集合于多对多关联(Collections of values and many-to-many associations)
column
(可选):保存集合元素值的字段名。
formula
(可选): 用于计算元素的SQL公式
<element column="column_name" (1) formula="any SQL expression" (2) type="typename" (3) length="L" precision="P" scale="S" not-null="true|false" unique="true|false" node="element-name" />
|
|
|
|
|
|
A many-to-many association is specified using the <many-to-many>
element.
<many-to-many column="column_name" (1) formula="any SQL expression" (2) class="ClassName" (3) fetch="select|join" (4) unique="true|false" (5) not-found="ignore|exception" (6) entity-name="EntityName" (7) property-ref="propertyNameFromAssociatedClass" (8) node="element-name" embed-xml="true|false" />
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
包含一组整数的bag(还设置了order-by
参数指定了迭代的顺序):
<set name="names" table="person_names"> <key column="person_id"/> <element column="person_name" type="string"/> </set>
一个实体数组,在这个案例中是一个多对多的关联(注意这里的实体是自动管理生命周期的对象(life cycle objects),cascade="all"
):
<bag name="sizes" table="item_sizes" order-by="size asc"> <key column="item_id"/> <element column="size" type="integer"/> </bag>
一个map,通过字符串的索引来指明日期:
<array name="addresses" table="PersonAddress" cascade="persist"> <key column="personId"/> <list-index column="sortOrder"/> <many-to-many column="addressId" class="Address"/> </array>
一个组件的列表:(下一章讨论)
<map name="holidays" table="holidays" schema="dbo" order-by="hol_name asc"> <key column="id"/> <map-key column="hol_name" type="string"/> <element column="hol_date" type="date"/> </map>
一对多关联(One-to-many Associations)
<list name="carComponents" table="CarComponents"> <key column="carId"/> <list-index column="sortOrder"/> <composite-element class="CarComponent"> <property name="price"/> <property name="type"/> <property name="serialNumber" column="serialNum"/> </composite-element> </list>
一个被包含的实体的实例只能被包含在一个集合的实例中
一个被包含的实体的实例只能对应于集合索引的一个值中
一个从Product
到Part
的关联需要关键字字段,可能还有一个索引字段指向Part
所对应的表。 <one-to-many>
标记指明了一个一对多的关联。
class
(必须):被关联类的名称。
<one-to-many class="ClassName" (1) not-found="ignore|exception" (2) entity-name="EntityName" (3) node="element-name" embed-xml="true|false" />
|
|
|
|
|
|
注意:<one-to-many>
元素不需要定义任何字段。 也不需要指定表名。
重要提示:如果一对多
关联中的外键字段定义成NOT NULL
,你必须把<key>
映射声明为not-null="true"
,或者使用双向关联,并且标明inverse="true"
。参阅本章后面关于双向关联的讨论。
下面的例子展示一个Part
实体的map,把name作为关键字。( partName
是Part
的持久化属性)。注意其中的基于公式的索引的用法。
<map name="parts" cascade="all"> <key column="productId" not-null="true"/> <map-key formula="partName"/> <one-to-many class="Part"/> </map>