How to use MongoRepository (Step-by-step)

This is a step-by-step example on how to use MongoRepository. In this example, for simplicity's sake, we will assume you're using NuGet to install MongoRepository.
  1. Start Visual Studio and create a new Console Application
  2. Make sure the "empty" application is saved
  3. Go to the Project menu and select Manage NuGet Packages...
  4. Make sure in the left pane the Online >> All option is selected and search in the top-right corner for MongoRepository
  5. Click MongoRepository (note: not ProMongoRepository; this is an unrelated project) and click the Install button
  6. NuGet will take care of downloading and installing MongoRepository and adding all required references to your project. You might have to accept 10gen's csharp-driver EULA.

Now we're all set up for business. We will now create a sample project with a simple list of customers having some products.

Adding configuration

First, we need to tell our application where the MongoDb server can be contacted and what database to use.
  1. Go to Project >> Add Item... (or Ctrl-Shift-A)
  2. Select Application Configuration File and click Add
  3. A file called App.config will be added to your project
  4. Edit the file to make sure it looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <connectionStrings>
    <add name="MongoServerSettings"
         connectionString="mongodb://localhost/SampleProject" />
  </connectionStrings>
</configuration>
More on connectionstrings can be found here. Since v1.4.1 MongoRepository will default to Acknowledged WriteConcern since it internally uses the new MongoClient object; you can still specify Unacknowledged Writeconcerns. The database name will be SampleProject. Don't worry if the database doesn't exist (yet). MongoDb will automatically create the database when required.

The connectionstring's name has to be MongoServerSettings as MongoRepository defaults to that name. If you don't want that, or want to provide more than one connectionstring then take a look in the Advanced usage section below.

Define entities

We'll add a few customers to our database; but to do that we need to create some entities first: Customer and Products.
  1. Go to Project >> Add Item... (or Ctrl-Shift-A)
  2. Select Class and make sure it's named "Entities.cs"; click Add
  3. Make sure the code looks like below:

using System.Collections.Generic;
using MongoRepository;

public class Customer : Entity  //Inherit from Entity!
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public List<Product> Products { get; set; }

    public Customer()
    {
        this.Products = new List<Product>();
    }
}

public class Product //No need to inherit from Entity; This object is not contained in
                     //it's "own" MongoDb document. It is only contained in a customer
{
    public string Name { get; set; }
    public decimal Price { get; set; }
}

NOTE Each Entity (or better: each class derived from Entity) will have an Id property of type string. MongoRepository will handle any conversions from/to ObjectId. This approach is chosen so that applications using MongoRepository will not be required to bother with implementation specific (e.g. MongoDb) details. The string type is a native member of the .Net BCL and therefore applications using MongoRepository will never need to reference any MongoDb assemblies; for advanced usage (see below) this might differ.

Use MongoRepository

Open Program.cs and edit it as below:

using System;
using System.Linq;
using MongoRepository;

class Program
{
    static MongoRepository<Customer> customerrepo = new MongoRepository<Customer>();

    static void Main(string[] args)
    {

        //Add customers
        var john = new Customer() { FirstName = "John", LastName = "Doe" };
        var jane = new Customer() { FirstName = "Jane", LastName = "Doe" };
        var jerry = new Customer() { FirstName = "Jerry", LastName = "Maguire" };
        customerrepo.Add(new[] { john, jane, jerry });

        //Show contents of DB
        DumpData();

        //Update customers
        john.FirstName = "Johnny";  //John prefers Johnny
        customerrepo.Update(john);

        jane.LastName = "Maguire";  //Jane divorces John and marries Jerry
        customerrepo.Update(jane);

        //Delete customers
        customerrepo.Delete(jerry.Id);  //Jerry passes away

        //Add some products to John and Jane
        john.Products.AddRange(new[] {
                new Product() { Name = "Fony DVD Player XY1299", Price = 35.99M },
                new Product() { Name = "Big Smile Toothpaste", Price = 1.99M }
        });
        jane.Products.Add(new Product() { Name = "Life Insurance", Price = 2500 });
        customerrepo.Update(john);
        customerrepo.Update(jane);
        //Or, alternatively: customerrepo.Update(new [] { john, jane });

        //Show contents of DB
        DumpData();

        //Finally; demonstrate GetById and First
        var mysterycustomer1 = customerrepo.GetById(john.Id);
        var mysterycustomer2 = customerrepo.First(c => c.FirstName == "Jane");

        Console.WriteLine("Mystery customer 1: {0} (having {1} products)",
                mysterycustomer1.FirstName, mysterycustomer1.Products.Count);
        Console.WriteLine("Mystery customer 2: {0} (having {1} products)",
                mysterycustomer2.FirstName, mysterycustomer2.Products.Count);

        //Delete all customers
        customerrepo.DeleteAll();

        //Halt for user
        Console.WriteLine("Press any key...");
        Console.ReadKey();
    }

    private static void DumpData()
    {
        //Print all data
        Console.WriteLine("Currently in our database:");
        foreach (Customer c in customerrepo)
        {
            Console.WriteLine("{0}\t{1}\t has {2} products",
                c.FirstName, c.LastName, c.Products.Count);
            foreach (Product p in c.Products)
                Console.WriteLine("\t{0} priced ${1:N2}", p.Name, p.Price);
            Console.WriteLine("\tTOTAL: ${0:N2}", c.Products.Sum(p => p.Price));
        }
        Console.WriteLine(new string('=', 50));
    }
}

Run the application. Output should be something like:
Currently in our database:
John    Doe      has 0 products
        TOTAL: $0,00
Jane    Doe      has 0 products
        TOTAL: $0,00
Jerry   Maguire  has 0 products
        TOTAL: $0,00
==================================================
Currently in our database:
Jane    Maguire  has 1 products
        Life Insurance priced $2.500,00
        TOTAL: $2.500,00
Johnny  Doe      has 2 products
        Fony DVD Player XY1299 priced $35,99
        Big Smile Toothpaste priced $1,99
        TOTAL: $37,98
==================================================
Mystery customer 1: Johnny (having 2 products)
Mystery customer 2: Jane (having 1 products)
Press any key...


Tip: A handy tool for visualising MongoDb's databases, collections, documents etc. is MongoVUE. If you remove, comment out or set a breakpoint at the line where the customers are deleted you can use this tool to quickly analyse what's going on in MongoDb.

Advanced usage

By default MongoRepository names the collection to store entities in as the entityname:

public class Customer : Entity
{
    //...
}

Collections are auto-created by MongoDb when they don't exist. The above example will cause MongoRepository to create a collection named Customer. If you prefer a different name for your collection you can override it by using the CollectioName attribute like this:

[CollectionName("MyCustomersCollection")]
class Customer : Entity
{
    //...
}

More advanced use like inherited types using BsonKnownTypes attributes might require you to add a reference to the C# driver's Serialization Attributes.

using MongoDB.Bson.Serialization.Attributes;

[CollectionName("MyAnimalsCollection")]
[BsonKnownTypes(typeof(Cat), typeof(Dog))]
public abstract class Animal : Entity { }

[CollectionName("MyCatLikesCollection")]
[BsonKnownTypes(typeof(Lion), typeof(Tiger))]
public class Cat : Animal { }

public class Dog : Animal { }

public class Lion : Cat { }

public class Tiger : Cat { }

Or using other attributes like BsonIgnore and BsonIgnoreIfNull:

using System.Collections.Generic;
using MongoRepository;
using MongoDB.Bson.Serialization.Attributes;

public class Customer : Entity  //Inherit from Entity!
{
    public string FirstName { get; set; }

    [BsonIgnore]
    public string LastName { get; set; }    //Ignore lastname

    [BsonIgnoreIfNull]
    public List<Product> Products { get; set; } //Ignore when no items in list
}

Usually you will want to create your own (derived) repositories exposing their own, domain specific, methods:

public class CustomerRepository : MongoRepository<Customer> {
    //...

    public List<Customer> GetCustomersWithOpenInvoices() {
        //...
    }

    public Customer GetCustomerWithLongestName() {
        //...
    }

    //...
}

Possibly (and ideally) you'll even want to create interfaces for these repositories (e.g. ICustomerRepository).

Should you ever need the ObjectId as an actual ObjectId instead of a string then you can easily get it back:

(Make sure you include using MongoDB.Bson;)
var X = new ObjectId(customer.Id);  //Hey, presto! X is now an ObjectId!
//See for yourself:
Console.WriteLine(X.CreationTime);
Console.WriteLine(X.Machine);
Console.WriteLine(X.Pid);
Console.WriteLine(X.Timestamp);

MongoRepository will, when inheriting from Entity, by default use ObjectId's (represented as string). If you want to use, for example, your own natural key for objects you can do so by not inheriting from Entity but by implementing IEntity:

public class Country : IEntity  //Implement IEntity
{
    //You could use, for instance, ISO 3166-1 alpha-2 codes (like EN, NL)
    public string Id { get; set; }

    //...

}

Managing the underlying MongoCollection

The MongoRepositoryManager<T> exposes some methods to manage the underlying MongoCollection. Using, for example, a MongoRepositoryManager<Customer> you can create or drop indexes and get the used storage size for the collection.
Note: This class is, for now, preliminary and a work-in-progress.

Last edited Oct 25, 2013 at 11:43 PM by RobIII, version 62