-
Notifications
You must be signed in to change notification settings - Fork 934
/
Copy pathcomponent_mapping.xml
366 lines (307 loc) · 14.2 KB
/
component_mapping.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
<chapter id="components">
<title>Component Mapping</title>
<para>
The notion of a <emphasis>component</emphasis> is re-used in several different contexts,
for different purposes, throughout NHibernate.
</para>
<sect1 id="components-dependentobjects">
<title>Dependent objects</title>
<para>
A component is a contained object that is persisted as a value type and not an entity
reference. The term "component" refers to the object-oriented notion of composition and
not to architecture-level components. For example, you can model a person like this:
</para>
<programlisting><![CDATA[public class Person
{
public virtual string Key { get; set; }
public virtual DateTime Birthday { get; set; }
public virtual Name Name { get; set; }
...
}]]></programlisting>
<programlisting><![CDATA[public class Name
{
public string First { get; set; }
public string Last { get; set; }
public char Initial { get; set; }
}]]></programlisting>
<para>
Now <literal>Name</literal> may be persisted as a component of
<literal>Person</literal>. <literal>Name</literal> defines getter
and setter methods for its persistent properties, but it does not need to declare
any interfaces or identifier properties.
</para>
<para>
Our NHibernate mapping would look like:
</para>
<programlisting><![CDATA[<class name="Eg.Person, Eg" table="person">
<id name="Key" column="pid" type="string">
<generator class="uuid.hex"/>
</id>
<property name="Birthday" type="date"/>
<component name="Name" class="Eg.Name, Eg"> <!-- class attribute optional -->
<property name="Initial"/>
<property name="First"/>
<property name="Last"/>
</component>
</class>]]></programlisting>
<para>
The person table would have the columns <literal>pid</literal>,
<literal>Birthday</literal>,
<literal>Initial</literal>,
<literal>First</literal> and
<literal>Last</literal>.
</para>
<para>
Like value types, components do not support shared references. In other words, two
persons could have the same name, but the two person objects would contain two
independent name objects that were only "the same" by value. The null
value semantics of a component are <emphasis>ad hoc</emphasis>. When reloading the
containing object, NHibernate will assume that if all component columns are
null, then the entire component is null. This is suitable for most purposes.
</para>
<para>
The properties of a component can be of any NHibernate type (collections, many-to-one
associations, other components, etc). Nested components should <emphasis>not</emphasis>
be considered an exotic usage. NHibernate is intended to support a fine-grained
object model.
</para>
<para>
The <literal><component></literal> element allows a <literal><parent></literal>
sub-element that maps a property of the component class as a reference back to the
containing entity.
</para>
<programlisting><![CDATA[<class name="Eg.Person, Eg" table="person">
<id name="Key" column="pid" type="string">
<generator class="uuid.hex"/>
</id>
<property name="Birthday" type="date"/>
<component name="Name" class="Eg.Name, Eg">
<parent name="NamedPerson"/> <!-- reference back to the Person -->
<property name="Initial"/>
<property name="First"/>
<property name="Last"/>
</component>
</class>]]></programlisting>
</sect1>
<sect1 id="components-incollections">
<title>Collections of dependent objects</title>
<para>
Collections of components are supported (eg. an array of type
<literal>Name</literal>). Declare your component collection by
replacing the <literal><element></literal> tag with a
<literal><composite-element></literal> tag.
</para>
<programlisting><![CDATA[<set name="SomeNames" table="some_names">
<key column="id"/>
<composite-element class="Eg.Name, Eg"> <!-- class attribute required -->
<property name="Initial"/>
<property name="First"/>
<property name="Last"/>
</composite-element>
</set>]]></programlisting>
<para>
Note: if you define an <literal>ISet</literal> of composite elements, it is
very important to implement <literal>Equals()</literal> and
<literal>GetHashCode()</literal> correctly.
</para>
<para>
Composite elements can contain components but not collections. If your composite
element contains components, use the
<literal><nested-composite-element></literal> tag. This case is a collection
of components which themselves have components. You may want to consider if a
one-to-many association is more appropriate. Remodel the composite element as an
entity, but be aware that even though the .Net model is the same, the relational
model and persistence semantics are still slightly different.
</para>
<para>
A special case of a composite element is a composite element with a nested
<literal><many-to-one></literal> element. This mapping allows you to map extra
columns of a many-to-many association table to the composite element class. The
following is a many-to-many association from
<literal>Order</literal> to <literal>Item</literal> where
<literal>PurchaseDate</literal>, <literal>Price</literal> and
<literal>Quantity</literal> are properties of the association:
</para>
<programlisting><![CDATA[<class name="Order" ... >
...
<set name="PurchasedItems" table="purchase_items">
<key column="order_id">
<composite-element class="Purchase">
<property name="PurchaseDate"/>
<property name="Price"/>
<property name="Quantity"/>
<many-to-one name="Item" class="Item"/> <!-- class attribute is optional -->
</composite-element>
</set>
</class>]]></programlisting>
<para>
There cannot be a reference to the purchase on the other side for bidirectional association
navigation. Components are value types and do not allow shared references. A single
<literal>Purchase</literal> can be in the set of an <literal>Order</literal>, but it cannot
be referenced by the <literal>Item</literal> at the same time.
</para>
<para>Even ternary (or quaternary, etc) associations are possible:</para>
<programlisting><![CDATA[<class name="Order" ... >
...
<set name="PurchasedItems" table="purchase_items">
<key column="order_id">
<composite-element class="OrderLine">
<many-to-one name="PurchaseDetails class="Purchase"/>
<many-to-one name="Item" class="Item"/>
</composite-element>
</set>
</class>]]></programlisting>
<para>
Composite elements can appear in queries using the same syntax as
associations to other entities.
</para>
</sect1>
<sect1 id="components-asmapindex">
<title>Components as IDictionary indices</title>
<para>
The <literal><composite-map-key></literal> element lets you map a
component class as the key of an <literal>IDictionary</literal>. Make sure
you override <literal>GetHashCode()</literal> and <literal>Equals()</literal>
correctly on the component class. See <xref linkend="collections-indexed"/>
for more information on the <literal><composite-map-key></literal>
element.
</para>
</sect1>
<sect1 id="components-compositeid">
<title>Components as composite identifiers</title>
<para>
You can use a component as an identifier of an entity class. Your component
class must satisfy certain requirements:
</para>
<itemizedlist spacing="compact">
<listitem>
<para>
It must be marked with the <literal>Serializable</literal> attribute.
</para>
</listitem>
<listitem>
<para>
It must re-implement <literal>Equals()</literal> and
<literal>GetHashCode()</literal>, consistently with the database's
notion of composite key equality.
</para>
</listitem>
<listitem>
<para>
It should re-implement <literal>ToString()</literal> if you consider
using the second level cache. See <xref linkend="NHibernate.Caches-howto" />.
</para>
</listitem>
</itemizedlist>
<para>
You cannot use an <literal>IIdentifierGenerator</literal> to generate composite keys.
Instead the application must assign its own identifiers.
</para>
<para>
Since a composite identifier must be assigned to the object before saving it,
you cannot use <literal>unsaved-value</literal> of the identifier to distinguish
between newly instantiated instances and instances saved in a previous session.
See <xref linkend="mapping-declaration-id-assigned"/> for more information.
</para>
<para>
Use the <literal><composite-id></literal> tag, with nested
<literal><key-property></literal> or <literal><key-many-to-one></literal>
elements, in place of the usual <literal><id></literal> declaration. For example,
the following <literal>OrderLine</literal> class has a primary key that depends upon
the (composite) primary key of <literal>Order</literal>.
</para>
<programlisting><![CDATA[<class name="OrderLine">
<composite-id name="Id" class="OrderLineId">
<key-property name="lineId"/>
<key-property name="orderId"/>
<key-property name="customerId"/>
</composite-id>
<property name="Name"/>
<many-to-one name="Order" class="Order"
insert="false" update="false">
<column name="orderId"/>
<column name="customerId"/>
</many-to-one>
...
</class>]]></programlisting>
<para>
Any foreign keys referencing the <literal>OrderLine</literal> table are now composite.
Declare this in your mappings for other classes. An association to
<literal>OrderLine</literal> is mapped like this:
</para>
<programlisting><![CDATA[<many-to-one name="OrderLine" class="OrderLine">
<!-- the "class" attribute is optional, as usual -->
<column name="lineId"/>
<column name="orderId"/>
<column name="customerId"/>
</many-to-one>]]></programlisting>
<para>
The <literal><column></literal> element is an alternative to the <literal>column</literal>
attribute everywhere. Using the <literal><column></literal> element is required for
composite keys, but also gives more declaration options, which are mostly useful when using
<literal>hbm2ddl</literal>. See <xref linkend="mapping-column" />.
</para>
<para>
A many-to-many association to <literal>OrderLine</literal> also uses the composite foreign key:
</para>
<programlisting><![CDATA[<set name="UndeliveredOrderLines">
<key column name="warehouseId"/>
<many-to-many class="OrderLine">
<column name="lineId"/>
<column name="orderId"/>
<column name="customerId"/>
</many-to-many>
</set>]]></programlisting>
<para>
The collection of <literal>OrderLine</literal> in <literal>Order</literal> would use:
</para>
<programlisting><![CDATA[<set name="OrderLines" inverse="true">
<key>
<column name="orderId"/>
<column name="customerId"/>
</key>
<one-to-many class="OrderLine"/>
</set>]]></programlisting>
<para>
The <literal><one-to-many></literal> element declares no columns.
</para>
<para>
If <literal>OrderLine</literal> itself owns a collection, it also has a composite foreign key.
</para>
<programlisting><![CDATA[<class name="OrderLine">
...
<list name="DeliveryAttempts">
<key> <!-- a collection inherits the composite key type -->
<column name="lineId"/>
<column name="orderId"/>
<column name="customerId"/>
</key>
<list-index column="attemptId" base="1"/>
<composite-element class="DeliveryAttempt">
...
</composite-element>
</set>
</class>]]></programlisting>
</sect1>
<sect1 id="components-dynamic">
<title>Dynamic components</title>
<para>
You can also map a property of type <literal>IDictionary</literal> or
<literal>IDictionary<string, object></literal>, or declared as a C#
<literal>dynamic</literal>:
</para>
<programlisting><![CDATA[<dynamic-component name="UserAttributes">
<property name="Foo" column="FOO"/>
<property name="Bar" column="BAR"/>
<many-to-one name="Baz" class="Baz" column="BAZ_ID"/>
</dynamic-component>]]></programlisting>
<para>
The semantics of a <literal><dynamic-component></literal> mapping are identical
to <literal><component></literal>. The advantage of this kind of mapping is
the ability to determine the actual properties of the component at deployment time, just
by editing the mapping document. Runtime manipulation of the mapping document is also
possible, using a DOM parser. You can also access, and change, NHibernate's
configuration-time metamodel via the <literal>Configuration</literal> object.
</para>
</sect1>
</chapter>