Code that accompanies this article can be downloaded here. (Notes: Tests in this code will pass only if MongoDB server is running on localhost:27017. Version 2.4.4 of MongoDB Driver is used).
In previous blog posts, Mongo DB basics part 1. and part 2. I covered some of the foundations of this database. In these articles, one can learn how to install MongoDB, create databases, collections, documents and how to use these entities. Also, there is a lot of information about distributing MongoDB, shards, and replica sets and how to manipulate with each of these entities. Readers can learn how this document NoSQL database functions, and what are perks of using it, as well as its downsides.
Nevertheless, there is no single line of code and everything is explained in more or less general manner. MongoDB Shell Client was used for demonstration of all crucial operations, so readers were not exposed to any coding lesions. That is why I’ll try to show here how MongoDB can be used from code, and do some of the operations, shown in previous articles, automatically. So, let’s take a look how MongoDB can be used in .NET, by implementing simple MongoDB CRUD Repository.
Installing MongoDB Driver
Guys from MongoDB provided a wide range of drivers for different programming languages. Drivers are just client libraries that application can use to communicate with Mongo Database. For .NET all we need to do is install NuGet package:
Install-Package MongoDB.Driver -Version 2.4.4
This will include three libraries in our project:
- MongoDB.Bson – library used to serialize, deserialize and do other forms of manipulation with BSON documents.
- MongoDB.Driver – the driver itself, used for communication with MongoDB.
- MongoDB.Driver.Core – infrastructure on which driver has been built.
Mapping BSON to strongly typed C# object
If you checked out my previous posts, you’ve learned that MongoDB stores documents in BSON format. Those are basically binary JSON files (ok, it is a little bit more complicated than that :)). When we use .NET driver we consume documents trough BsonDocument. What we want to do in this exercise is to map those BsonDocuments to strongly typed C# objects. But before that, let’s first see how our database and its entities look like.
For purposes of this exercise, we will use database called – blog. This database has a collection – users, and this collection contains document for each user. JSON document for the individual user would look like something like this:
An equivalent of this in C# looks like this:
You will notice that there are attributes for each property of this class. These attributes allow us to automatically map data from BsonDocument to our class. BsonId is used to map unique document identifier. Every document in MongoDB has this element, and its type is ObjectId. BsonElement(field_name) is used to map other fields from the object on the object properties.
Since we know that document databases don’t have a strict schema, it is possible to have more fields in the JSON document then we really want to use in our application. Also, it is possible that we don’t want to pick up all the fields from the database. For this, we can use BsonIgnoreExtraElements attribute on the class itself.
The main goal of this exercise is to create a class which will give us the ability to do simple CRUD operations on users collection. The first thing we need to do is connect to the database from our application. The easiest way to do this is to use MongoClient class. It accepts connection string so we will have to provide this.
Alternatively, MongoClientSettings class can be used, which provide various possibilities. One of the interesting ones is ClusterConfiguration property, which is of ClusterBuilder type, used for configuring clusters. Other classes that we need to use are MongoDatabase, to access defined database (blog in this case), and MongoCollection, to access defined collection (users in this case). Here is how that looks like in the code:
Ok, this is pretty straightforward. Still, there is one thing that should be noted. MongoCollection is defined using Users as a template type, and this is possible only because we added those attributes to Users class. The other way to achieve this is by using BsonDocument, but then we have to map fields manually to properties of Users class.
Inserting document in the database is done easily once previous steps have been followed:
Obviously, I have used asynchronous operation InsertOneAsync, but you can use synchronous one too. Again, because we mapped JSON fields on Users properties, it is easy to work with these operations.
Reading users is done like this:
There are three different implementations of this functionality. Let’s go through each of them.
GetAllUsers returns all users from the database. We use the Find method of the MongoCollection class to do so, and pass empty BsonDocument into it. In the next method, GetUsersByField method, we can see that this Find method actually receives filter object, which it will use as criteria for getting the data.
In the first function, we use an empty filter and thus receive all users from the collection. In second, we use Builder to create the filter which will be used against the database. Finally, the last function – GetUsers uses Skip and Limit methods of MongoCollection to get a necessary chunk of data. For example, this last function can be used for paging.
Documents can be updated in a similar manner:
In this example, function UpdateOneAsync is used, but if you want to change values of multiple documents you can use UpdateMultipleAsync. Also, synchronous siblings of these operations also exist.
Another interesting fact is that using this function you can add fields that are not in the “schema”. For example, if you want to add a new field in the user document, you can do this:
This way the big MongoDB’s (and rest of the document databases) feature of a modular schema is harnessed. You are not blocked by defined objects, you can store information dynamically if you need to do so.
And finally, users can be deleted this way:
Pretty straightforward, don’t you think? Same as in Reading examples, Builder was used for creating a filter.
Adding indexes is a bit different. If we want to do it dynamically, the easiest way is to use BsonDocument(. Here is how it is done:
On the other hand, if we know what our indexes will be beforehand, we can use strongly typed implementation like this:
Here, in one simple example, we went through many of MongoDB Driver’s features. We learned how to map JSON documents to .NET objects, which gave us an easy way to use rest of the features. CRUD operations, which are most commonly used, have been showed and explained, too.
In general, one could see how to use MongoDB features with C# in .NET environment.
Read full MongoDB Serial here.
Read more posts from the author at Rubik’s Code.