用于映射集合类的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" table="table_name" schema="schema_name" lazy="true|extra|false" inverse="true|false" cascade="all|none|save-update|delete|all-delete-orphan|delete-orphan" sort="unsorted|natural|comparatorClass" order-by="column_name asc|desc" where="arbitrary sql where condition" fetch="join|select|subselect" batch-size="N" access="field|property|ClassName" optimistic-lock="true|false" mutable="true|false" 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开始)。
<map-key column="column_name" formula="any SQL expression" type="type_name" node="@attribute-name" length="N"/>
|
|
|
|
|
<map-key-many-to-many column="column_name" formula="any SQL expression" class="ClassName" />
|
|
|
|
|
假若你的表没有一个索引字段,当你仍然希望使用List
作为属性类型,你应该把此属性映射为Hibernate <bag>。从数据库中获取的时候,bag不维护其顺序,但也可选择性的进行排序。
从集合类可以产生很大一部分映射,覆盖了很多常见的关系模型。我们建议你试验schema生成工具,来体会一下不同的映射声明是如何被翻译为数据库表的。
任何值集合或者多对多关联需要专用的具有一个或多个外键字段的collection table、一个或多个collection element column,以及还可能有一个或多个索引字段。
对于一个值集合, 我们使用<element>
标签。
<element column="column_name" formula="any SQL expression" type="typename" length="L" precision="P" scale="S" not-null="true|false" unique="true|false" node="element-name" />
|
|
|
|
|
多对多关联(many-to-many association) 使用
<many-to-many>
元素定义.
<many-to-many column="column_name" formula="any SQL expression" class="ClassName" fetch="select|join" unique="true|false" not-found="ignore|exception" entity-name="EntityName" property-ref="propertyNameFromAssociatedClass" node="element-name" embed-xml="true|false" />
|
|
|
|
|
|
|
|
为此关联打开外连接抓取或者后续select抓取。这是特殊情况;对于一个实体及其指向其他实体的多对多关联进全预先抓取(使用一条单独的 |
|
对外键字段允许DDL生成的时候生成一个惟一约束。这使关联变成了一个高效的一对多关联。(此句存疑:原文为This makes the association multiplicity effectively one to many.) |
|
|
|
|
|
|
例子:首先, 一组字符串:
<set name="names" table="NAMES"> <key column="GROUPID"/> <element column="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>
一对多关联通过外键连接两个类对应的表,而没有中间集合表。 这个关系模型失去了一些Java集合的语义:
一个被包含的实体的实例只能被包含在一个集合的实例中
一个被包含的实体的实例只能对应于集合索引的一个值中
一个从Product
到Part
的关联需要关键字字段,可能还有一个索引字段指向Part
所对应的表。 <one-to-many>
标记指明了一个一对多的关联。
<one-to-many class="ClassName" not-found="ignore|exception" entity-name="EntityName" node="element-name" embed-xml="true|false" />
|
|
|
|
|
例子
<set name="bars"> <key column="foo_id"/> <one-to-many class="org.hibernate.Bar"/> </set>
注意:<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>