6.2. 集合映射( Collection mappings )

优质
小牛编辑
131浏览
2023-12-01

提示

从集合类可以产生很大一部分映射,覆盖了很多常见的关系模型。我们建议你试验 schema 生成工具,来体会一下不同的映射声明是如何被翻译为数据库表的。

用于映射集合类的 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="prop(1)ertyName"
    table="tab(2)le_name"
    schema="sc(3)hema_name"
    lazy="true(4)|extra|false"
    inverse="t(5)rue|false"
    cascade="a(6)ll|none|save-update|delete|all-delete-orphan|delete-orphan"
    sort="unso(7)rted|natural|comparatorClass"
    order-by="(8)column_name asc|desc"
    where="arb(9)itrary sql where condition"
    fetch="joi(10)n|select|subselect"
    batch-size(11)="N"
    access="fi(12)eld|property|ClassName"
    optimistic(13)-lock="true|false"
    mutable="t(14)rue|false"
    node="element-name|."
    embed-xml="true|false"
>

    <key .... />
    <map-key .... />
    <element .... />
</map
>

1

name:集合属性的名称

2

table(可选——默认为属性的名称)这个集合表的名称(不能在一对多的关联关系中使用)。

3

schema(可选):表的 schema 的名称,他将覆盖在根元素中定义的 schema

4

lazy(可选--默认为 true)可以用来关闭延迟加载(false):指定一直使用预先抓取,或者打开 "extra-lazy" 抓取,此时大多数操作不会初始化集合类(适用于非常大的集合)。

5

inverse(可选 — 默认为 false)标记这个集合作为双向关联关系中的方向一端。

6

cascade(可选 — 默认为 none)让操作级联到子实体。

7

sort(可选)指定集合的排序顺序,其可以为自然的(natural)或者给定一个用来比较的类。

8

order-by(可选,仅用于 jdk1.4):指定表的字段(一个或几个)再加上 asc 或者 desc(可选),定义 Map、Set 和 Bag 的迭代顺序。

9

where(可选):指定任意的 SQL where 条件,该条件将在重新载入或者删除这个集合时使用(当集合中的数据仅仅是所有可用数据的一个子集时这个条件非常有用)。

10

fetch(可选,默认为 select):用于在外连接抓取、通过后续 select 抓取和通过后续 subselect 抓取之间选择。

11

batch-size(可选,默认为 1):指定通过延迟加载取得集合实例的批处理块大小("batch size")。

12

access(可选-默认为属性 property):Hibernate 取得集合属性值时使用的策略。

13

乐观锁(可选 - 默认为 true):对集合的状态的改变会是否导致其所属的实体的版本增长(对一对多关联来说,关闭这个属性常常是有理的)。

14

mutable(可变)(可选 — 默认为 true):若值为 false,表明集合中的元素不会改变(在某些情况下可以进行一些小的性能优化)。

6.2.1. 集合外键(Collection foreign keys)

集合实例在数据库中依靠持有集合的实体的外键加以辨别。此外键作为集合关键字段(collection key column)(或多个字段)加以引用。集合关键字段通过 <key> 元素映射。

在外键字段上可能具有非空约束。对于大多数集合来说,这是隐含的。对单向一对多关联来说,外键字段默认是可以为空的,因此你可能需要指明 not-null="true"


<key column="productSerialNumber" not-null="true"/>

外键约束可以使用 ON DELETE CASCADE


<key column="productSerialNumber" on-delete="cascade"/>

<key> 元素的完整定义,请参阅前面的章节。

6.2.2. 集合元素(Collection elements)

集 合几乎可以包含任何其他的 Hibernate 类型,包括所有的基本类型、自定义类型、组件,当然还有对其他实体的引用。存在一个重要的区别:位于集合中的对象可能是根据“值”语义来操作(其声明周期 完全依赖于集合持有者),或者它可能是指向另一个实体的引用,具有其自己的生命周期。在后者的情况下,被作为集合持有的状态考虑的,只有两个对象之间的 “连接”。

被包容的类型被称为集合元素类型(collection element type)。集合元素通过 <element><composite-element> 映射,或在其是实体引用的时候,通过 <one-to-many><many-to-many> 映射。前两种用于使用值语义映射元素,后两种用于映射实体关联。

6.2.3. 索引集合类(Indexed collections)

所有的集合映射,除了 set 和 bag 语义的以外,都需要指定一个集合表的索引字段(index column) — 用于对应到数组索引,或者 List 的索引,或者 Map 的关键字。通过 <map-key>Map 的索引可以是任何基础类型;若通过 <map-key-many-to-many>,它也可以是一个实体引用;若通过 <composite-map-key>,它还可以是一个组合类型。数组或列表的索引必须是 integer 类型,并且使用 <list-index> 元素定义映射。被映射的字段包含有顺序排列的整数(默认从 0 开始)。

<list-index
        column(1)="column_name"
        base="(2)0|1|..."/>

1

column_name (required): the name of the column holding the collection index values.

1

base (optional - defaults to 0): the value of the index column that corresponds to the first element of the list or array.

<map-key
        column(1)="column_name"
        formul(2)a="any SQL expression"
        type="(3)type_name"
        node="@attribute-name"
        length="N"/>

1

column (optional): the name of the column holding the collection index values.

2

formula (optional): a SQL formula used to evaluate the key of the map.

3

type (required): the type of the map keys.

<map-key-many-to-many
        column(1)="column_name"
        formul(2)(3)a="any SQL expression"
       
/>

1

column (optional): the name of the foreign key column for the collection index values.

2

formula (optional): a SQ formula used to evaluate the foreign key of the map key.

3

class (required): the entity class used as the map key.

假若你的表没有一个索引字段,当你仍然希望使用 List 作为属性类型,你应该把此属性映射为 Hibernate <bag>。从数据库中获取的时候,bag 不维护其顺序,但也可选择性的进行排序。

6.2.4. 值集合于多对多关联(Collections of values and many-to-many associations)

任何值集合或者多对多关联需要专用的具有一个或多个外键字段的 collection table、一个或多个 collection element column,以及还可能有一个或多个索引字段。

对于一个值集合,我们使用 <element> 标签。例如:

<element
        column(1)="column_name"
        formul(2)a="any SQL expression"
        type="(3)typename"
        length="L"
        precision="P"
        scale="S"
        not-null="true|false"
        unique="true|false"
        node="element-name"
/>

1

column (optional): the name of the column holding the collection element values.

2

formula (optional): an SQL formula used to evaluate the element.

3

type (required): the type of the collection element.

A many-to-many association is specified using the <many-to-many> element.

<many-to-many
        column(1)="column_name"
        formul(2)a="any SQL expression"
        class=(3)"ClassName"
        fetch=(4)"select|join"
        unique(5)="true|false"
        not-fo(6)und="ignore|exception"
        entity(7)-name="EntityName"
        proper(8)ty-ref="propertyNameFromAssociatedClass"
        node="element-name"
        embed-xml="true|false"
    />

1

column (optional): the name of the element foreign key column.

2

formula (optional): an SQL formula used to evaluate the element foreign key value.

3

class (required): the name of the associated class.

4

fetch (optional - defaults to join): enables outer-join or sequential select fetching for this association. This is a special case; for full eager fetching in a single SELECT of an entity and its many-to-many relationships to other entities, you would enable join fetching,not only of the collection itself, but also with this attribute on the <many-to-many> nested element.

5

unique (optional): enables the DDL generation of a unique constraint for the foreign-key column. This makes the association multiplicity effectively one-to-many.

6

not-found (optional - defaults to exception): specifies how foreign keys that reference missing rows will be handled: ignore will treat a missing row as a null association.

7

entity-name (optional): the entity name of the associated class, as an alternative to class.

8

property-ref (optional): the name of a property of the associated class that is joined to this foreign key. If not specified, the primary key of the associated class is used.

下面是一些例子:

一系列字符串:


<set name="names" table="person_names">
    <key column="person_id"/>
    <element column="person_name" type="string"/>
</set
>

包含一组整数的 bag(还设置了 order-by 参数指定了迭代的顺序):


<bag name="sizes"
        table="item_sizes" 
        order-by="size asc">
    <key column="item_id"/>
    <element column="size" type="integer"/>
</bag
>

一个实体数组,在这个案例中是一个多对多的关联(注意这里的实体是自动管理生命周期的对象(lifecycle objects),cascade="all"):


<array name="addresses"
        table="PersonAddress" 
        cascade="persist">
    <key column="personId"/>
    <list-index column="sortOrder"/>
    <many-to-many column="addressId" class="Address"/>
</array
>

一个 map,通过字符串的索引来指明日期:


<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
>

一个组件的列表:(将在下一章讨论)


<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
>

6.2.5. 一对多关联(One-to-many Associations)

一对多关联通过外键连接两个类对应的表,而没有中间集合表。 这个关系模型失去了一些 Java 集合的语义:

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

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

一个从 ProductPart 的关联需要关键字字段,可能还有一个索引字段指向 Part 所对应的表。<one-to-many> 标记指明了一个一对多的关联。

<one-to-many
        class=(1)"ClassName"
        not-fo(2)und="ignore|exception"
        entity(3)-name="EntityName"
        node="element-name"
        embed-xml="true|false"
    />

1

class(必需):被关联类的名称。

2

not-found(可选 - 默认为exception):指明若缓存的标示值关联的行缺失,该如何处理:ignore 会把缺失的行作为一个空关联处理。

3

entity-name(可选):被关联的类的实体名,作为 class 的替代。

注意:<one-to-many> 元素不需要定义任何字段。也不需要指定表名。

警告

重要提示:如果一对多关联中的外键字段定义成 NOT NULL,你必须把 <key> 映射声明为 not-null="true",或者使用双向关联,并且标明 inverse="true"。参阅本章后面关于双向关联的讨论。

下面的例子展示一个 Part 实体的 map,把 name 作为关键字。( partNamePart 的持久化属性)。注意其中的基于公式的索引的用法。


<map name="parts"
        cascade="all">
    <key column="productId" not-null="true"/>
    <map-key formula="partName"/>
    <one-to-many class="Part"/>
</map
>