Skip to content

Commit d637e88

Browse files
Class Mapping (#58)
1 parent c7a4270 commit d637e88

File tree

1 file changed

+330
-0
lines changed

1 file changed

+330
-0
lines changed

source/fundamentals/class-mapping.txt

Lines changed: 330 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,330 @@
1+
.. _csharp-class-mapping:
2+
3+
=============
4+
Class Mapping
5+
=============
6+
7+
.. contents:: On this page
8+
:local:
9+
:backlinks: none
10+
:depth: 2
11+
:class: singlecol
12+
13+
Overview
14+
--------
15+
16+
In this guide, you can learn how to customize the way the {+driver-long+}
17+
maps BSON documents to and from {+language+} classes. You should read this page
18+
to learn more about the default class mapping behavior, or if you need to
19+
customize the way the driver serializes or deserializes your data.
20+
21+
Automatic Class Mapping
22+
-----------------------
23+
24+
When you use a class, rather than a ``BsonDocument``, to represent data in a
25+
MongoDB collection, the {+driver-short+} automatically creates a **class map**
26+
that it uses to serialize or deserialize your data. It does this mapping by matching
27+
the name of the field in the document to the name of the property in the class.
28+
29+
.. important::
30+
31+
The type of the property in your class should match the type of the field in
32+
the document. The {+driver-short+} instantiates a serializer based on the
33+
type of the property in your class. If the types don't match when the driver
34+
attempts to deserialize the data, the serializer throws an exception.
35+
36+
Manually Creating A Class Map
37+
-----------------------------
38+
39+
You can bypass the driver's automatic class mapping functionality, and manually
40+
define the class map by using the ``RegisterClassMap()`` method.
41+
42+
The following example defines a ``Person`` class:
43+
44+
.. code-block:: csharp
45+
46+
public class Person
47+
{
48+
public string Name { get; set; }
49+
public int Age { get; set; }
50+
public List<string> Hobbies {get; set;}
51+
}
52+
53+
The following code demonstrates how to register the class map for the ``Person``
54+
class:
55+
56+
.. code-block:: csharp
57+
58+
BsonClassMap.RegisterClassMap<Person>(classMap =>
59+
{
60+
classMap.MapMember(p => p.Name);
61+
classMap.MapMember(p => p.Age);
62+
classMap.MapMember(p => p.Hobbies);
63+
});
64+
65+
.. important::
66+
67+
You must register a class map *before* it's needed in your code. We recommend
68+
registering class maps prior to initializing a connection with MongoDB.
69+
70+
You can also manually map a subset of class properties, while still
71+
allowing the driver to automatically map the remaining properties. To do this,
72+
register a class map and call the ``AutoMap()`` method before manually
73+
specifying your properties.
74+
75+
In the following code example, the ``AutoMap()`` method maps all properties
76+
of the ``Person`` class, then manually adjusts the mapping for the ``Hobbies``
77+
field:
78+
79+
.. code-block:: csharp
80+
81+
BsonClassMap.RegisterClassMap<Person>(classMap =>
82+
{
83+
classMap.AutoMap();
84+
classMap.MapMember(p => p.Hobbies).SetElementName("favorite_hobbies");
85+
});
86+
87+
Customize Class Serialization
88+
-----------------------------
89+
90+
You can customize how the driver serializes and deserializes documents at the class
91+
level by using attributes with the class or by calling methods while registering
92+
a class map.
93+
94+
Ignore Extra Elements
95+
~~~~~~~~~~~~~~~~~~~~~
96+
97+
When a BSON document is deserialized to a {+language+} class, the {+driver-short+}
98+
looks at the name of each field in the document and tries to find a matching property
99+
name in the class. By default, if a field in the document doesn't have a match in the class,
100+
the driver throws an exception.
101+
102+
You can choose to ignore any elements that do
103+
not have a matching class property by using the ``BsonIgnoreExtraElements`` attribute.
104+
This prevents the driver from throwing an exception, and maps any other fields
105+
that have matching class properties.
106+
107+
The following example shows how to add a ``BsonIgnoreExtraElements`` attribute
108+
to a class.
109+
110+
.. code-block:: csharp
111+
112+
[BsonIgnoreExtraElements]
113+
public class Person
114+
{
115+
public string Name { get; set; }
116+
public int Age { get; set; }
117+
public List<string> Hobbies {get; set;}
118+
}
119+
120+
You can also ignore any extra elements when registering a class map:
121+
122+
.. code-block:: csharp
123+
124+
BsonClassMap.RegisterClassMap<Person>(classMap =>
125+
{
126+
classMap.AutoMap();
127+
classMap.SetIgnoreExtraElements(true);
128+
});
129+
130+
Using Class Discriminators
131+
~~~~~~~~~~~~~~~~~~~~~~~~~~
132+
133+
You can specify **discriminators** to help identify **polymorphic** classes that
134+
are serialized to the same collection. Polymorphic classes are classes that
135+
inherit properties and methods from a parent class. A discriminator is an
136+
element that's added to a document to identify which class the document was
137+
serialized from.
138+
139+
You can specify a discriminator using the ``BsonDiscriminator`` attribute as
140+
follows:
141+
142+
.. code-block:: csharp
143+
144+
[BsonDiscriminator("personClass")]
145+
public class Person
146+
{
147+
public string Name { get; set; }
148+
public int Age { get; set; }
149+
public List<string> Hobbies {get; set;}
150+
}
151+
152+
You can also specify a discriminator when registering a class map as follows:
153+
154+
.. code-block:: csharp
155+
156+
BsonClassMap.RegisterClassMap<Person>(classMap =>
157+
{
158+
classMap.AutoMap();
159+
classMap.SetDiscriminator("personClass");
160+
});
161+
162+
In BSON, discriminators have the field name ``_t``.
163+
164+
The following example shows how a document from the ``Person`` class with the
165+
"personClass" discriminator appears in the collection after serialization:
166+
167+
.. code-block:: json
168+
169+
{ "_id": "...", "_t": "personClass", "Name": "...", "Age": "...", "Hobbies": [...]}
170+
171+
.. TODO: Link to page on polymorphism/discriminators
172+
173+
Mapping with Constructors
174+
-------------------------
175+
176+
By default, the {+driver-short+} can automatically map a class only if the class has
177+
a constructor with no arguments. If you want the driver to use a constructor that accepts
178+
one or more arguments, you can add the ``BsonConstructor`` attribute to the constructor.
179+
In this case, the driver the driver examines the types to determine how to map the
180+
constructor arguments to class properties or fields.
181+
182+
When the driver creates a class map for the following ``Person`` class, it will use the
183+
constructor marked with the ``BsonConstructor`` attribute. The ``name`` argument will
184+
map to the ``Name`` property and the ``age`` argument will map to the ``Age`` property.
185+
186+
.. code-block:: csharp
187+
:emphasize-lines: 7
188+
189+
public class Person
190+
{
191+
public string Name { get; set; }
192+
public int Age { get; set; }
193+
public List<string> Hobbies {get; set;}
194+
195+
[BsonConstructor]
196+
public Person(string name, string age)
197+
{
198+
Name = name;
199+
Age = age;
200+
}
201+
}
202+
203+
.. tip:: Multiple ``BsonConstructor`` attributes
204+
205+
If there is more than one constructor with the ``BsonConstructor``
206+
attribute, the driver uses the constructor that has the most
207+
parameters with matching fields in the document.
208+
209+
You can also specify the constructor to use when registering your class map:
210+
211+
.. code-block:: csharp
212+
:emphasize-lines: 17
213+
214+
public class Person
215+
{
216+
public string Name { get; set; }
217+
public int Age { get; set; }
218+
public List<string> Hobbies {get; set;}
219+
220+
public Person(string name, string age)
221+
{
222+
Name = name;
223+
Age = age;
224+
}
225+
}
226+
227+
BsonClassMap.RegisterClassMap<Person>(classMap =>
228+
{
229+
classMap.AutoMap();
230+
classMap.MapCreator(p => new Person(p.Name, p.Age));
231+
});
232+
233+
Customize Property Serialization
234+
--------------------------------
235+
236+
You can customize how the driver serializes a class property by
237+
adding attributes to the property. For more information about custom
238+
property serialization, see :ref:`csharp-custom-serialization`.
239+
240+
Support Extra Elements
241+
~~~~~~~~~~~~~~~~~~~~~~
242+
243+
You can design your {+language+} class to store any extra elements in your
244+
document that don't have matching class properties. To do this your class must
245+
have a ``BsonDocument`` type property to hold the extra elements.
246+
247+
The following code uses the ``BsonExtraElements`` attribute with the
248+
``ExtraElements`` property to direct the driver to store extra elements:
249+
250+
.. code-block:: csharp
251+
252+
public class Person
253+
{
254+
public string Name { get; set;
255+
public int Age { get; set; }
256+
public List<string> Hobbies {get; set;}
257+
[BsonExtraElements]
258+
public BsonDocument ExtraElements {get; set;}
259+
}
260+
261+
You can also support extra elements when initializing a class map as follows:
262+
263+
.. code-block:: csharp
264+
265+
BsonClassMap.RegisterClassMap<Person>(classMap =>
266+
{
267+
classMap.AutoMap();
268+
classMap.MapExtraElementsMember(p => p.ExtraElements);
269+
});
270+
271+
.. note::
272+
273+
After the driver serializes a class with extra elements back to BSON, the
274+
extra elements may not be in the same order as they were in the original
275+
document.
276+
277+
Dynamically Serialize Properties
278+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
279+
280+
You can use a method to determine whether or not to serialize a property. For
281+
the driver to automatically use the method when serializing, you must prefix the
282+
method name with ``ShouldSerialize`` followed by the name of the property that
283+
the method applies to. When the driver sees a method with this naming
284+
convention, it uses that method to determine whether or not to serialize
285+
properties that have the provided property name.
286+
287+
The following example creates a method that only serializes the ``Age`` property
288+
if its value is not equal to ``0``. The driver does not serialize any properties
289+
whose values don't meet this requirement:
290+
291+
.. code-block:: csharp
292+
293+
public class Person
294+
{
295+
public string Name { get; set; }
296+
public int Age { get; set; }
297+
public List<string> Hobbies {get; set;}
298+
299+
public bool ShouldSerializeAge()
300+
{
301+
return Age != 0;
302+
}
303+
}
304+
305+
You can also specify the method while registering a class map:
306+
307+
.. code-block:: csharp
308+
309+
BsonClassMap.RegisterClassMap<Employee>(classMap =>
310+
{
311+
classMap.AutoMap();
312+
classMap.MapMember(p => c.Age).SetShouldSerializeMethod(
313+
obj => ((Person) obj).Age != 0
314+
);
315+
});
316+
317+
Additional Information
318+
----------------------
319+
320+
For more information on using {+language+} classes, see :ref:`csharp-poco`.
321+
322+
API Documentation
323+
-----------------
324+
325+
- `BsonClassMap
326+
<{+api-root+}/T_MongoDB_Bson_Serialization_BsonClassMap_1.htm>`__
327+
- `RegisterClassMap
328+
<{+api-root+}/M_MongoDB_Bson_Serialization_BsonClassMap_RegisterClassMap__1_1.htm>`__
329+
- `AutoMap
330+
<{+api-root+}/M_MongoDB_Bson_Serialization_BsonClassMap_AutoMap.htm>`__

0 commit comments

Comments
 (0)