Inheritance

collinsauve edited this page Sep 24, 2010 · 5 revisions
Clone this wiki locally

Inheritance

Inheritance has first class support in MongoDB-CSharp. We have chosen to use discriminators to define which type of class is stored in the database. This way, all entities in the inheritance chain are all stored in the same MongoDB collection. This allows queries to be issues for types in the inheritance chain at once.

Any value is allowed for the discriminator so there is no need to have a strong link between a type’s name and its discriminator value in the database. The only caveat to this is that you must let us know about any subclasses prior to deserializing them. Otherwise, we wouldn’t know about the mapping. This is done off of a MongoConfiguration object using the Map() method.

By default, we use an “_t” as the discriminator key because it is small. Since keys are stored for every value, it is better to keep them smaller in most cases.

Below is an example of an animal hierarchy and their default discriminator values.

abstract class Animal
{ 
  public Oid Id { get; set; }

  public int Age { get; set; }
}

//Bear will have a discriminator value of "Bear"
class Bear : Animal
{ }
//a MongoDB Bear document would like {_id: "ObjectId(etc...)", _t: "Bear", Age: 3}


//Cat will have a discriminator value of "Cat"
abstract class Cat : Animal
{ }

//Tiger will have a discriminator value of ["Cat", "Tiger"]
class Tiger : Cat
{ }
//a MongoDB Tiger document would like {_id: "ObjectId(etc...)", _t: ["Cat", "Tiger"], Age: 3}

//Lion will have a discriminator value of ["Cat", "Lion"]
class Lion : Cat
{ }
//a MongoDB Lion document would like {_id: "ObjectId(etc...)", _t: ["Cat", "Lion"], Age: 3}

Configuring

Configuring the classes so that the discriminator will be saved you need to add the IsSubClassOf


//Create a configuration builder
var config = new MongoConfigurationBuilder();
//Define the mapping for the base class and it's concrete implementations
config.Mapping(mapping =>
{
    mapping.DefaultProfile(profile =>
    {      
        profile.SubClassesAre(t => t.IsSubclassOf(typeof(Animal)));
    });
    mapping.Map<Bear>();
    mapping.Map<Cat>();
    mapping.Map<Lion>();
    mapping.Map<Tiger>();
});
//You need to add the connection string to the configuration
//when creating a mongo with the configuration
config.ConnectionString("Server=127.0.0.1");
//Create the Mongo with the configuration
Mongo mongo = new Mongo(config.BuildConfiguration());
mongo.Connect();

Querying

When using Typed Collections, MongoDB-CSharp automatically adds in the relevant discriminators when saving the documents and when querying. Below are some examples:

Root level query.

This will pull back all animals over the age of 10.

//C# code
GetCollection<Animal>().Find(x => x.Age > 10);

//json query
{ "Age" : {$gt: 10 } }

Middle level query.

This will pull back all Cats over the age of 10.

//C# code
GetCollection<Cat>().Find(x => x.Age > 10);

//json query
{"_t": "Cat", "Age" : {$gt: 10 } }

Leaf level query.

This will pull back all Tigers over the age of 10.

//C# code
GetCollection<Tiger>().Find(x => x.Age > 10);

//json query
{"_t": ["Cat", "Tiger"], "Age" : {$gt: 10 } }