组合元素有个特别的案例,是组合元素可以包含一个<many-to-one> 元素。类似这样的映射允许你映射一个many-to-mang关联表作为组合元素额外的字段。(A mapping like this allows you to map extra columns of a many-to-many association table to the composite element class.) 接下来的的例子是从Order到Item的一个多对多的关联关系,而 purchaseDate, price 和 quantity 是Item的关联属性。
<class name="eg.Order" .... >
....
<set name="purchasedItems" table="purchase_items" lazy="true">
<key column="order_id">
<composite-element class="eg.Purchase">
<property name="purchaseDate"/>
<property name="price"/>
<property name="quantity"/>
<many-to-one name="item" class="eg.Item"/> <!-- class attribute is optional -->
</composite-element>
</set>
</class>
即使三重或多重管理都是可能的:
<class name="eg.Order" .... >
....
<set name="purchasedItems" table="purchase_items" lazy="true">
<key column="order_id">
<composite-element class="eg.OrderLine">
<many-to-one name="purchaseDetails" class="eg.Purchase"/>
<many-to-one name="item" class="eg.Item"/>
</composite-element>
</set>
</class>
在查询中,组合元素使用的语法是和关联到其他实体的语法一样的。
7.3. 组件作为Map的索引(Components as Map indices )
<composite-index>元素允许你映射一个Component类作为Map的key, 但是你必须确定你正确的在这个类中重写了hashCode() 和 equals()方法。
7.4. 组件作为联合标识符(Components as composite identifiers)
你可以使用一个component作为一个实体类的标识符。 你的component类必须满足以下要求:
它必须实现java.io.Serializable接口
它必须重新实现equals()和hashCode()方法, 始终和组合关键字在数据库中的概念保持一致
你不能使用一个IdentifierGenerator产生组合关键字。作为替代应用程序必 须分配它自己的标识符.
既然联合标识符必须在对象存储之前被分配,我们就不能使用标识符的unsaved-value来把刚刚新建的实例和在先前的session保存的实例区分开来。
如果你希望使用saveOrUpdate()或者级联保存/更新(cascading save / update),你应该实现 Interceptor.isUnsaved()。使用<composite-id> 标签(它和<component>标签有同样的属性和元素)代替<id>标签。 下面有个联合标识符类的定义:
<class name="eg.Foo" table"FOOS">
<composite-id name="compId" class="eg.FooCompositeID">
<key-property name="string"/>
<key-property name="short"/>
<key-property name="date" column="date_" type="date"/>
</composite-id>
<property name="name"/>
....
</class>
这时候,任何到FOOS的外键也同样是联合的, 在你其他类的映射文件中也必须同样定义。 一个到Foo的定义应该像以下这样:
<many-to-one name="foo" class="eg.Foo">
<!-- the "class" attribute is optional, as usual -->
<column name="foo_string"/>
<column name="foo_short"/>
<column name="foo_date"/>
</many-to-one>
新的 <column> 标签同样被用于包含多个字段的自定义类型(This new columntag is also used by multi-column custom types)。 事实上在各个地方它都是一个可选的字段属性。要定义一个元素是Foo的集合类,要这样写:
<set name="foos">
<key column="owner_id"/>
<many-to-many class="eg.Foo">
<column name="foo_string"/>
<column name="foo_short"/>
<column name="foo_date"/>
</many-to-many>
</set>
另一方面,<one-to-many>元素通常不定义字段.
如果 Foo 自己包含集合, 那么他们也需要使用联合外键。
<class name="eg.Foo">
....
....
<set name="dates" lazy="true">
<key> <!-- a collection inherits the composite key type -->
<column name="foo_string"/>
<column name="foo_short"/>
<column name="foo_date"/>
</key>
<element column="foo_date" type="date"/>
</set>
</class>
7.5. 动态组件 (Dynamic components)
你甚至可以映射Map类型的属性:
<dynamic-component name="userAttributes">
<property name="foo" column="FOO"/>
<property name="bar" column="BAR"/>
<many-to-one name="baz" class="eg.Baz" column="BAZ"/>
</dynamic-component>
从<dynamic-component>映射的语义上来讲,它和<component>是相同的。 这种映射类型的优点在于通过修改映射文件,就可以具有在部署时检测真实属性的能力.(利用一个DOM解析器, 是有可能在运行时刻操作映射文件的。)