Skip to content

Commit bf8656d

Browse files
authored
DOCSP-24551: POCOs page (#31)
* DOCSP-24551: work with POCOs * first pass fixes * PR comments 1 * small fixes * PR comments 2 * add detail * list reword
1 parent fb6ad6b commit bf8656d

File tree

3 files changed

+344
-1
lines changed

3 files changed

+344
-1
lines changed

source/fundamentals.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ Fundamentals
1212

1313
/fundamentals/connection
1414
/fundamentals/crud
15-
/fundamentals/builders
15+
/fundamentals/builders
16+
/fundamentals/poco

source/fundamentals/poco.txt

Lines changed: 282 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
1+
.. _csharp-poco:
2+
3+
===============
4+
Work with POCOs
5+
===============
6+
7+
.. default-domain:: mongodb
8+
9+
.. contents:: On this page
10+
:local:
11+
:backlinks: none
12+
:depth: 2
13+
:class: singlecol
14+
15+
Overview
16+
--------
17+
18+
In this guide, you can learn about how you can use ":wikipedia:`Plain Old CLR/Class
19+
Objects <Plain_old_CLR_object>`", or **POCOs**, with the {+driver-short+} for your operations
20+
and queries. POCOs are simple class objects that do not inherit
21+
features from any framework-specific base class and do not return any
22+
special types. We recommend using POCOs in your {+language+} code to
23+
adhere to idiomatic driver usage and achieve the best performance.
24+
25+
You should read this guide if you want to learn more about how to use
26+
POCOs with the {+driver-short+} or if you need to adjust the driver's default
27+
field mapping behavior.
28+
29+
Create a POCO
30+
-------------
31+
32+
You can create a POCO by defining a simple class that does not
33+
implement interfaces or extend classes from a framework. When you
34+
execute an operation such as a read or write using a POCO, the driver
35+
internally *serializes*, or converts, the POCO to BSON.
36+
37+
Select the :guilabel:`POCO` or :guilabel:`BSON` tab to see how the
38+
driver serializes a sample POCO to BSON:
39+
40+
.. tabs::
41+
42+
.. tab:: POCO
43+
:tabid: poco-representation
44+
45+
.. code-block:: csharp
46+
:copyable: false
47+
48+
public class Clothing
49+
{
50+
public ObjectId Id { get; set; }
51+
public string Name { get; set; }
52+
public bool InStock { get; set; }
53+
public double Price { get; set; }
54+
public List<string> ColorSelection { get; set; }
55+
}
56+
57+
.. tab:: BSON
58+
:tabid: bson-representation
59+
60+
.. code-block:: json
61+
:copyable: false
62+
63+
{
64+
"_id": ObjectId("..."),
65+
"Name": "Long Sleeve Shirt",
66+
"InStock": true,
67+
"Price": 17.99,
68+
"ColorSelection": [ "black", "navy", "red" ]
69+
}
70+
71+
You can define a POCO with any object structure that suits your
72+
needs, including nested objects, arrays, lists, and any data types.
73+
74+
Custom Serialization
75+
--------------------
76+
77+
If the default field mapping behavior does not meet your needs, you can
78+
specify custom behavior using serialization-related attributes. These
79+
attributes change the way that the driver serializes each property of
80+
your POCO. This section describes some of the common
81+
serialization-related attributes.
82+
83+
Set Field Names
84+
~~~~~~~~~~~~~~~
85+
86+
The driver serializes POCO properties to BSON fields with the same field
87+
name and capitalization. To store a property under a different name, use
88+
the ``[BsonElement()]`` attribute. The following code maps the
89+
``YearBuilt`` property of the ``House`` class to the ``year_built``
90+
field in the serialized BSON document:
91+
92+
.. code-block:: csharp
93+
:copyable: true
94+
95+
public class House
96+
{
97+
public ObjectId Id { get; set; }
98+
99+
[BsonElement("year_built")]
100+
public int YearBuilt { get; set; }
101+
}
102+
103+
Though it is common to use the Pascal case naming convention when
104+
defining {+language+} classes, using the ``[BsonElement()]`` attribute
105+
allows you to select a different or custom naming convention in your
106+
MongoDB collection.
107+
108+
.. tip:: Set Custom Field Name Convention
109+
110+
If you want to serialize every property with a custom field name, you
111+
can define a ``ConventionPack`` instead of using the
112+
``[BsonElement()]`` attribute. For example, if you define your class
113+
using the Pascal case naming convention, you can use the following
114+
code to use camel case field names in the serialized document:
115+
116+
.. literalinclude:: ../includes/fundamentals/code-examples/poco.cs
117+
:start-after: start-conventionpack
118+
:end-before: end-conventionpack
119+
:language: csharp
120+
:copyable:
121+
:dedent:
122+
123+
Select Type Representation
124+
~~~~~~~~~~~~~~~~~~~~~~~~~~
125+
126+
To serialize a {+language+} property to a specific BSON type, use the
127+
``[BsonRepresentation()]`` attribute. This works only if the
128+
{+language+} primitive type is convertible to the BSON type you specify.
129+
In the following code sample, the ``YearBuilt`` property, defined as a
130+
``char`` in {+language+}, is serialized as a BSON ``Int32`` type:
131+
132+
.. code-block:: csharp
133+
:copyable: true
134+
135+
public class House
136+
{
137+
public ObjectId Id { get; set; }
138+
139+
[BsonRepresentation(BsonType.Int32)]
140+
public char YearBuilt { get; set; }
141+
}
142+
143+
For more information on valid type conversions, see the `{+language+}
144+
Conversions Specification
145+
<https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/conversions>`__.
146+
147+
Set Field Order
148+
~~~~~~~~~~~~~~~
149+
150+
The driver serializes properties to BSON fields in the order they
151+
are specified in the POCO. To store properties in a custom order to
152+
match an existing schema, you can specify the ``Order`` named
153+
parameter in the ``[BsonElement()]`` attribute. In the following code
154+
sample, the driver stores the ``YearBuilt`` property after the
155+
``Style`` property:
156+
157+
.. code-block:: csharp
158+
:copyable: true
159+
160+
public class House
161+
{
162+
public ObjectId Id { get; set; }
163+
164+
[BsonElement(Order = 2)]
165+
public int YearBuilt { get; set; }
166+
167+
[BsonElement(Order = 1)]
168+
public string Style { get; set; }
169+
}
170+
171+
If any properties don't have an explicit ``Order``, the driver will
172+
serialize them in the default order after those that do.
173+
174+
Identify ``Id`` Property
175+
~~~~~~~~~~~~~~~~~~~~~~~~
176+
177+
By default, the driver maps any public property named ``Id``, ``id``, or
178+
``_id`` to the BSON ``_id`` field. To explicitly select the
179+
property to map to the ``_id`` field, use the ``[BsonId()]`` attribute.
180+
The following code sample maps the ``Identifier`` property to the
181+
``_id`` field:
182+
183+
.. code-block:: csharp
184+
:copyable: true
185+
186+
public class House
187+
{
188+
[BsonId]
189+
public string Identifier { get; set; }
190+
}
191+
192+
.. warning:: Multiple Id Fields
193+
194+
If you identify more than one property as the ``_id`` field using the
195+
``[BsonId()]`` attribute, the driver throws a
196+
``DuplicateBsonMemberMapAttributeException``. If your POCO
197+
properties use more than one of the three recognized field
198+
names (``Id``, ``id``, and ``_id``), the driver throws a
199+
``BsonSerializationException``.
200+
201+
Omit Empty Fields
202+
~~~~~~~~~~~~~~~~~
203+
204+
By default, the driver serializes undefined properties to fields with ``null``
205+
values. To ignore undefined properties during serialization, use the ``[BsonIgnore()]``
206+
attribute. The following code shows how you can prevent the driver from
207+
serializing the ``YearBuilt`` property if it is undefined:
208+
209+
.. code-block:: csharp
210+
:copyable: true
211+
212+
public class House
213+
{
214+
public ObjectId Id { get; set; }
215+
216+
[BsonIgnore]
217+
public int YearBuilt { get; set; }
218+
public string Style { get; set; }
219+
}
220+
221+
Example
222+
-------
223+
224+
The following example shows how to insert a ``Clothing`` document with custom field
225+
mapping specifications into MongoDB.
226+
227+
The following code defines the ``Clothing`` class with these
228+
serialization-related attributes:
229+
230+
- ``[BsonElement()]``, which specifies custom field names in the camel case naming convention
231+
- ``[BsonRepresentation()]``, which specifies serialization of the ``Price`` field as a BSON ``Double`` type
232+
233+
.. literalinclude:: ../includes/fundamentals/code-examples/poco.cs
234+
:start-after: start-model
235+
:end-before: end-model
236+
:language: csharp
237+
:copyable:
238+
:dedent:
239+
240+
The following code instantiates a ``Clothing`` object and inserts the document into a collection:
241+
242+
.. literalinclude:: ../includes/fundamentals/code-examples/poco.cs
243+
:start-after: start-insert
244+
:end-before: end-insert
245+
:language: csharp
246+
:copyable:
247+
:dedent:
248+
249+
The BSON representation of the inserted document looks like this:
250+
251+
.. code-block:: json
252+
:copyable: false
253+
254+
{
255+
"_id": ObjectId("..."),
256+
"name": "Denim Jacket",
257+
"inStock": false,
258+
"price": 32.99,
259+
"colorSelection": [ "dark wash", "light wash" ]
260+
}
261+
262+
Additional Information
263+
----------------------
264+
265+
For a full list of serialization-related attributes, see the
266+
`Serialization.Attributes API documentation <{+api-root+}/N_MongoDB_Bson_Serialization_Attributes.htm>`__.
267+
268+
For additional read and write operation examples using POCOs, see the :ref:`Usage Examples
269+
<csharp-usage-examples>` or the :ref:`CRUD Fundamentals Pages <csharp-crud>`.
270+
271+
API Documentation
272+
~~~~~~~~~~~~~~~~~
273+
274+
To learn more about any of the methods or types discussed in this
275+
guide, see the following API documentation:
276+
277+
- `[BsonElement()] <{+api-root+}/T_MongoDB_Bson_Serialization_Attributes_BsonElementAttribute.htm>`__
278+
- `[BsonRepresentation()] <{+api-root+}/T_MongoDB_Bson_Serialization_Attributes_BsonRepresentationAttribute.htm>`__
279+
- `[BsonId()] <{+api-root+}/T_MongoDB_Bson_Serialization_Attributes_BsonIdAttribute.htm>`__
280+
- `[BsonIgnore()] <{+api-root+}/T_MongoDB_Bson_Serialization_Attributes_BsonIgnoreAttribute.htm>`__
281+
- `ConventionPack <{+api-root+}/T_MongoDB_Bson_Serialization_Conventions_ConventionPack.htm>`__
282+
- `InsertOne() <{+api-root+}/M_MongoDB_Driver_IMongoCollection_1_InsertOne.htm>`__
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
using MongoDB.Driver;
2+
using MongoDB.Bson;
3+
using MongoDB.Bson.Serialization.Attributes;
4+
5+
namespace TestRun.Fundamentals;
6+
7+
public class Poco
8+
{
9+
private static IMongoCollection<Clothing> _myColl;
10+
private static string _mongoConnectionString = "<Your MongoDB URI>";
11+
12+
public static void Main(string[] args)
13+
{
14+
Setup();
15+
16+
// start-insert
17+
var doc = new Clothing()
18+
{
19+
Name = "Denim Jacket",
20+
InStock = false,
21+
Price = 32.99m,
22+
ColorSelection = new List<string>() {"dark wash", "light wash"}
23+
};
24+
25+
_myColl.InsertOne(doc);
26+
// end-insert
27+
}
28+
private static void Setup()
29+
{
30+
// start-conventionpack
31+
var camelCaseConvention = new ConventionPack { new CamelCaseElementNameConvention() };
32+
ConventionRegistry.Register("CamelCase", camelCaseConvention, type => true);
33+
// end-conventionpack
34+
35+
// Establish the connection to MongoDB and get the restaurants database
36+
var mongoClient = new MongoClient(_mongoConnectionString);
37+
var myDatabase = mongoClient.GetDatabase("sample_db");
38+
_myColl = myDatabase.GetCollection<Clothing>("sample_coll");
39+
}
40+
}
41+
42+
// start-model
43+
public class Clothing
44+
{
45+
public ObjectId Id { get; set; }
46+
47+
[BsonElement("name")]
48+
public string Name { get; set; }
49+
50+
[BsonElement("inStock")]
51+
public bool InStock { get; set; }
52+
53+
[BsonElement("price")]
54+
[BsonRepresentation(BsonType.Double)]
55+
public decimal Price { get; set; }
56+
57+
[BsonElement("colorSelection")]
58+
public List<string> ColorSelection { get; set; }
59+
}
60+
// end-model

0 commit comments

Comments
 (0)