Writing my own NoSql DB?

Yesterday I got a thought:

why not write something very simple that can store object-graphs without mappings and other fuss.

Yes I know there’s MongoDb, RavenDb and several others, but it’s always a great deal of fun to write something of your own. So, inspired by Ayende’s technology choices, I spent a few hours last night just fiddling around with Lucene.Net and Json.Net. The result:

A simple model

public class Address
{
    public string Street { get; set; }
    public string Zip { get; set; }
    public string City { get; set; }
    public string Country { get; set; }
}

public class Customer
{
    [Key]
    public Guid? Id { get; set; }

    [Index]
    public string Firstname { get; set; }

    [Index]
    public string Lastname { get; set; }
        
    [Index]
    public int ShoppingIndex { get; set; }

    public Address BillingAddress { get; private set; }
    public Address DeliveryAddress { get; private set; }

    public Customer()
    {
        BillingAddress = new Address();
        DeliveryAddress = new Address();
    }
}

Consuming a Storage-provider

var customer = new Customer
                    {
                        Id = Guid.NewGuid(),
                        Firstname = "Daniel",
                        Lastname = "Wertheim",
                        ShoppingIndex = 99
                    };
customer.DeliveryAddress.Country = "Sweden";

var store = new LuceneStructureStore();
store.Insert(customer);

var refetched = store.GetByKey<Customer>(customer.Id.ToString());
...
...

Maybe it will grow to something useful. In the meantime I will continue my work with my MongoDB-provider, Simple-MongoDB.

//Daniel

Simple-MongoDB – Part 2, Anonymous types, JSON, Embedded entities and references

This is the second article of me showing some features in the Simple-MongoDB driver. This time I will explore more ways of inserting data. More specifically, I will look at how-to insert Anonymous types as well as how-to insert entities described with JSON. Finally we will look at how to deal with embedded documents and relationships between entities, so called references.

Other writings in this series

Sample code

The sample code from this second article, is available for download here. Note! It also contains the code from previous parts in this series, but there has been some updates to the code, hence if you want to get your hands on the code for a specific article, use the download link in that specific article.

Flexibility

One of my goals with my driver was that it shouldn’t be tied to a certain key-value based class, like the Document-class in the MongoDB-CSharp-driver. I know that the team behind that driver, currently are implementing this as well. Simple-MongoDB relies on JSON.Net from Newtonsoft for dealing with serialization and deserialization of objects, hence I get support for dealing with anonymous types, JSON etc. Let’s look at how it get reflected in the API.

Anonymous types

The Entitystore lets you store anonymous types but will then not be able to automatically insert the document in the correct collection, which means that you have to manually specify the entity name. Note, that I wrote “the entity name” and NOT the collection name. Why? Because the Entitystore works with entities and will i.e pluralize the specified entity name (if you haven’t turned off pluralization, which is enabled by default).

Insert using anonymous type

var sessionFactory = new SimoSessionFactory();
using (var session = sessionFactory.GetSession(Constants.ConnectionStringName))
{
    var entityStore = new SimoEntityStore(session, Constants.DatabaseName);

    var note = new
                    {
                        Text = "This is a note, created using anonymous type.",
                        Tags = new[] { "Anonymous types", "Part 2" }
                    };

    entityStore.Insert("Notes", note);
}

Raw JSON

You can of course write/generate the JSON and pass that to the Entitystore. Again, just as with anonymous types, you have to specify the entity name.

There’s also a class “SimoJson” that takes a raw JSON-string in the constructor. If you are dealing with raw JSON, it’s preferred to use the SimoJson-class.

Insert using raw JSON

var sessionFactory = new SimoSessionFactory();
using (var session = sessionFactory.GetSession(Constants.ConnectionStringName))
{
    var entityStore = new SimoEntityStore(session, Constants.DatabaseName);

    var rawJson = @"{ 
        Text : ""This is a note, created using raw Json-string."", 
        Tags : [""Raw Json-string"", ""Part 2""] }";

    entityStore.Insert("Notes", rawJson);
}

Insert using raw JSON

var json = new SimoJson(@"{ 
    Text : ""This is a note, created using SimoJson-type."", 
    Tags : [""SimoJson-type"", ""Part 2""] }");

entityStore.Insert("Notes", json);

Embedded documents

MongoDB supports embedded documents, and I like to see them as value-object (as in the context of Domain-driven design). The embedded document has the same lifetime as the entity that it’s assigned to, hence it’s not the same as a relationship.

Insert a Note with an embedded Note

var sessionFactory = new SimoSessionFactory();
using (var session = sessionFactory.GetSession(Constants.ConnectionStringName))
{
    var entityStore = new SimoEntityStore(session, Constants.DatabaseName);

    var note = new Note
                        {
                            Text = "This is a note with an embeded note, created using entity.",
                            Tags = new[] { "Note with embeded note", "Part 2" },
                            SubNote = new Note{Text = "This is a subnote that is embeded."}
                        };

    entityStore.Insert<Note>(note);
}

References

MongoDB supports references and to make use of them in Simple-MongoDB, you consume the SimoReference-class or the SimoReference-class. The generic version lets you specify the type of the _id-field. Currently, it supports:

  • Guid
  • int
  • long
  • string

Read more about the different types.

To use the standard MongoDB _id-hash, use the SimoReference-class. It will generate the hash from date-time, computer, sequence etc. The Reference holds information about, in which collection the referenced document exists and which _id-value it has.

Insert a Note with a reference

var sessionFactory = new SimoSessionFactory();
using (var session = sessionFactory.GetSession(Constants.ConnectionStringName))
{
    var entityStore = new SimoEntityStore(session, Constants.DatabaseName);

    var user = new User {Username = "daniel"};

    var note = new Note
    {
        Text = "This is a note with an embeded note, created using entity.",
        Tags = new[] { "Note with embeded note", "Part 2" },
        WriterReference = entityStore.Reference<User>(user._id)
    };

    entityStore.Insert(user);
    entityStore.Insert(note);
}

The EntityStore.Reference function uses generics to specify to collection and the _id-value comes from the entity. Both Note and User extends Entity, which contains a property _id : SimoId. I use the SimoAutoId as the statebag so that I don’t have to manually ensure that the _id : SimoId gets a generated _id-value. I could have done this in the constructor by using SimoId.NewId().

One simple query

So, I will finish with showing you how-to perform queries using an Entity as template. The next article will deal with the various querying techniques, and by then I will hopefully have simplified the querying of references.

Query using Entity as template

var sessionFactory = new SimoSessionFactory();
using (var session = sessionFactory.GetSession(Constants.ConnectionStringName))
{
    var entityStore = new SimoEntityStore(session, Constants.DatabaseName);
    var selector = new Note
    {
        _id = null,
        Text = "This is a note with an embeded note, created using entity."
    };

    var notes = entityStore.Find<Note>(selector);
}

The _id is autogenerated in the Note’s base class Entity, and we want to query all notes having the text, hence we need to null the _id.

That’s it for now. Don’t forget to download the sample-code.

//Daniel

Simple-MongoDB – Part 1, Getting started

So, I thought it was time for me to write a “Getting started with MongoDB” article but instead of using Sam Corder’s driver, I will use my own: “Simple-MongoDB”. It will be a series of posts covering this topic. This post is the first and will cover how-to get connected and how-to add some entities.

Requirements

Step 1 – Download Simple-MongoDB

Head over to the project site: http://code.google.com/p/simple-mongodb and download the code. There’s two Zip-files:

  • Pls-SimpleMongoDb – v[X]-Bin.zip: Contains the release-compiled dll
  • Pls-SimpleMongoDb – v[X]-Source.zip: Contains the Visual Studio 2010 Solution

The latest code is of course available via the Trunk.

Step 2 – Create a new project

Create a new project and add a reference to the Pls.SimpleMongoDB.dll (if you test with an Console-application, ensure that to switch to Full .Net 4.0 framework and not just Client profile).

Step 3 – Get connected with the MongoDB server

This article shows how to consume the App.config and shows how to manually use the sessionfactory, which is something you probably would let your IoC handle for you.

App.config – Connectionstring

<connectionStrings>
  <add name="Pls.Simo.GettingStarted" connectionString="host:localhost;port:27017"/>
</connectionStrings>

Establish a connected Session

var sessionFactory = new SimoSessionFactory();
using (var session = sessionFactory.GetSession("Pls.Simo.GettingStarted"))
{
    //...
}

If you want to go with the default values from MongoDB {host : localhost, port : 27017 }; you can just use the sessionFactory.GetSession() – overload instead:

using (var session = sessionFactory.GetSession())
{
    //...
}

Step 4 – Add some data

Simple-MongoDB is designed to work with typed-classes, anonymous types as well as JSON-strings. We will start by looking at the typed-classes scenario. The simplest way to store entities is by consuming the EntityStore-API. It lies on-top of the Session-API and is designed to work with entities. The type-name of an entity is implicitly used as the collectionname and by default, consumes Microsofts Pluralizer to pluralize namings. This can of course be turned of (entityStore.Session.Pluralizer.Disable();).

Using the EntityStore-API

var sessionFactory = new SimoSessionFactory();
using (var session = sessionFactory.GetSession("Pls.Simo.GettingStarted"))
{
    var entityStore = new SimoEntityStore(session, "MyDatabase");

    var interestingUrl = new InterestingUrl(@"http://daniel.wertheim.se") { Description = "Some good writings about the Simple-MongoDB driver." };
    interestingUrl.SetTags("Simple-MongoDB", "Blog");
    entityStore.Insert(interestingUrl);
}

You can of course consume the Session-API, if you want. It also contains some methods that the EntityStore doesn’t. The Session-API lets you get references to databases and collections, and the work with them in a way that mimics MongoDB.

Using the Session-API

var sessionFactory = new SimoSessionFactory();
using (var session = sessionFactory.GetSession("Pls.Simo.GettingStarted"))
{
    var db = session["MyDatabase"];
    var collection = db.GetCollection<InterestingUrl>();

    var interestingUrl = new InterestingUrl(@"http://code.google.com/p/simple-mongodb") { Description = "The home of the Simple-MongoDB driver." };
    interestingUrl.SetTags("Simple-MongoDB", "Project site");
    collection.Insert(interestingUrl);
}

You can of course get a reference to the collection by specifying a string. But remember to take control of the pluralization.

var collection = session["MyDatabase"]["InterestingUrls"];

Step 5 – Querying

You can query by sending: either a JSON-string, anonymous-typ, typed C# class; as the selector to the Find-methods. There is a Fluent querying API that lets you help with the generation of JSON-query strings. To get more info on querying, look here: http://www.mongodb.org/display/DOCS/Advanced+Queries

Using anonymous type

var sessionFactory = new SimoSessionFactory();
using (var session = sessionFactory.GetSession("Pls.Simo.GettingStarted"))
{
    var entityStore = new SimoEntityStore(session, "MyDatabase");

    var interestingUrl = entityStore.FindOne<InterestingUrl>(new { Url = @"http://daniel.wertheim.se" });
}

Using Query-expression
The query-expression operates on the fluent Query-API and translates the query to JSON, which is then passed to the selector.

var sessionFactory = new SimoSessionFactory();
using (var session = sessionFactory.GetSession("Pls.Simo.GettingStarted"))
{
    var entityStore = new SimoEntityStore(session, "MyDatabase");

    var interestingUrl = entityStore.FindOne<InterestingUrl>(
        q => q["Url"].IsEq(@"http://code.google.com/p/simple-mongodb").And("Tags").HasAll("Simple-MongoDB", "Project site"));
}

That’s it for now. The next post will be posted shortly and will deal with Querying.

Download sample with code from this article.

//Daniel

Simple-MongoDB – Simplified Querying

I just checked in some code to simplify querying. I will just let the code speak for itself.

var q = new Query()["Name"].In("Daniel", "Sue").And("Age").Gt(21).And().Lt(29);
var persons = entityStore.Find(q.ToString());

So far it only supports:

  • $in
  • $where
  • $lt
  • $lte
  • $gt
  • $gte

More info about the operators

I will continue the work with the inner design of this Querying-code, but the API will be the same. I will of course add more operators to.

//Daniel

Simple-MongoDB – Querying

Updated: Read more about Simplified Querying

So I keep getting questions about how to write queries in Simple-MongoDB. I will try to get time documenting this, but until then, and since I relly on JSON, you could attack the problem like this:

To take an example, today I got a question about how to handle OR queries. If you have a look at the documentation (http://www.mongodb.org/display/DOCS/OR+operations+in+query+expressions) you find that it isn’t implemented in v1.4 but you can use the $where-operator.

$where-operator – Using JSON

var persons = entityStore.Find<Person>(@"{$where : ""this.Name == 'Daniel' || this.Name == 'Sue'""}");

or

var persons = session[DbName][PersonsCollectionName].Find<Person>(@"{$where : ""this.Name == 'Daniel' || this.Name == 'Sue'""}");

$where-operator – Using the Simo-WhereOperator

var persons = entityStore.Find<Person>(new WhereOperator(@"this.Name == 'Daniel' || this.Name == 'Sue'"));

or

var persons = session[DbName][PersonsCollectionName].Find<Person>(new WhereOperator(@"this.Name == 'Daniel' || this.Name == 'Sue'"));

$in-operator – Using JSON

var persons = entityStore.Find<Person>(@"{Name : { $in : [""Daniel"", ""Sue""] } }");

or

var persons = session[DbName][PersonsCollectionName].Find<Person>(@"{Name : { $in : [""Daniel"", ""Sue""] } }");

$in-operator – Using the Simo-InOperator

var persons = entityStore.Find<Person>(new InOperator("Name", "Daniel", "Sue"));

or

var persons = session[DbName][PersonsCollectionName].Find<Person>(new InOperator("Name", "Daniel", "Sue"));

The code can be aquired at the Google-code, project site.

//Daniel

Simple-MongoDB – Now runs against MongoDB v1.4

Just checked in a new version of Simple-MongoDB that now runs against MongoDB v1.4.

It now also runs on an improved version of Newtonsoft’s Json.Net library, which has gained a improved BSON-writer and built in support for regex, hence my custom version of this lib is no longer necessary.

Go download and play with it and come up with suggestions and patches or why not join up and be a part of the team.

I will focus on implementing more/better querying support and write some examples of this. There’s hopefully also coming support for lazy-loading etc. via an add-on-project, by the help of Rei Roldan.

//Daniel

Simple-MongoDB – Implicit support for Cursors

Minor update just checked in. The Source-code as well as binaries can be downloaded here.

I have reworked the underlying command-objects that are used to communicate with the MongoDb-server (Note! These are consumed by the EntityStore and Session API, hence you as an end user doesn’t have to use these commands). I have now implemented implicit-support for cursors. So if a query of yours gives more result then the query could return per request, additional request will be sent until the cursor has been emptied. Each resultset is appended to the Response-object of your query, so you don’t have to take care of this.

Example
Five persons exists in the db, and the QueryCommand doesn’t specify a Selector, hence all five will be returned. But since the NumberOfDocumentsToReturn is explicitly set to two, there will be three requests performed.

[TestMethod]
public void QueryManyPersonsUsingCursor_SpecificNumberOfDocumentsToReturnGivesCursor_AllPersonsAreReturned()
{
    var person = new[]
                 {
                     new Person { Name = "Daniel1", Age = 28 },
                     new Person { Name = "Daniel2", Age = 29 },
                     new Person { Name = "Daniel3", Age = 30 },
                     new Person { Name = "Daniel4", Age = 31},
                     new Person { Name = "Daniel5", Age = 32}
                 };
    InsertDocuments(Constants.Collections.PersonsFullCollectionName, person);

    using (var cn = CreateConnection())
    {
        var queryCommand = new QueryDocumentsCommand<Person>(cn)
        {
            NodeName = Constants.Collections.PersonsFullCollectionName,
            NumberOfDocumentsToReturn = 2
        };
        queryCommand.Execute();

        Assert.AreEqual(5, queryCommand.Response.NumberOfDocuments);
    }
}

When you are using the Session-API or the EntityStore-API, the NumberOfDocumentsToReturn is sat to zero, which means that the default value specified by the db will be used. Neverthless, you don’t have to think about the cursor.

//Daniel

Simple-MongoDB – Support for Regex and custom Id’s

So, it took a little bit longer than anticipated, but I just checked in support for regular expressions and custom Id’s support in references, in my C# based MongoDB driver, Simple-MongoDB. I had to add support for regexs to the Newtonsoft Json.Net library, so as of right now, Simple-MongoDB uses a custom dll for this, but I have uploaded the patch to Json.Net, so hopefully it will reach the main-branch in a couple of days.

Download here

Regular expressions

To make use of regular expressions you make use of the class SimoRegex. You can of course combine this with other criteria as well.

Code example – Regular expressions

[TestMethod]
public void Find_UsingRegex()
{
    var cn = CreateConnection();
    using (var session = new SimoSession(cn))
    {
        var entityStore = new SimoEntityStore(session, DbName);

        entityStore.Insert(new Person { Name = "Daniel", Age = 29 });
        entityStore.Insert(new Person { Name = "Daniel1", Age = 45 });
        entityStore.Insert(new Person { Name = "Daniel1", Age = 55 });
        entityStore.Insert(new Person { Name = "Daniel2", Age = 65 });
        entityStore.Insert(new Person { Name = "Sue", Age = 20 });

        var refetched = entityStore.FindOne<Person>(new { Age = 45, Name = new SimoRegex("^Dan.*1") });

        Assert.AreEqual(45, refetched.Age);
        Assert.AreEqual("Daniel1", refetched.Name);
    }
}

Custom Id’s in references

The supported Id-types when setting up references are now:

  • SimoId
  • Guid
  • int
  • long
  • string

Code example – SimoId

[TestMethod]
public void ParentChildReference_Example()
{
    var cn = CreateConnection();
    using (var session = new SimoSession(cn))
    {
        var entityStore = new SimoEntityStore(session, DbName);

        //The parent generates a new _id when created.
        //That _id is then used in the reference which is attached to the child.
        //After that, you just store the items.
        var parent = new Parent { Name = "Daniel" };
        var fatherReference = entityStore.Reference<Parent>(parent._id);
        var child = new Child { Name = "Isabell", FatherReference = fatherReference };

        //You could of course have created the reference manually, but then you loose the
        //use of the pluralizer, and have to role-this on your own.
        //new SimoReference { CollectionName = "Parents", Id = parent._id };

        entityStore.Insert(parent);
        entityStore.Insert(child);

        var refetchedChild = entityStore.FindOne<Child>(new { child._id });

        Assert.AreEqual(fatherReference.Id, refetchedChild.FatherReference.Id);
        Assert.AreEqual(fatherReference.CollectionName, refetchedChild.FatherReference.CollectionName);
    }
}

Code example – Guid as id
In this example I make use of Guid’s for identification. I do this in conjunction with anonymous types, but of course could have made the example cleaner by using static-typed Parent and Child as in the previous example.

[TestMethod]
public void ParentChildReference_CustomId_Example()
{
    var cn = CreateConnection();
    using (var session = new SimoSession(cn))
    {
        var entityStore = new SimoEntityStore(session, DbName);

        //This time we use anonymous type and custom Id's (Guids).
        var parent = new { _id = Guid.NewGuid(), Name = "Daniel" };
        var fatherReference = entityStore.Reference("Parent", parent._id);
        var child = new { _id = Guid.NewGuid(), Name = "Isabell", FatherReference = fatherReference };

        //You could of course have created the reference manually, but then you loose the
        //use of the pluralizer, and have to role-this on your own.
        //new SimoReference<Guid> { CollectionName = "Parents", Id = parent._id };

        entityStore.Insert("Parent", parent);
        entityStore.Insert("Child", child);

        var refetchedChild = entityStore.FindOne(infered: child, entityName: "Child", selector: new { child._id });

        Assert.AreEqual(fatherReference.Id, refetchedChild.FatherReference.Id);
        Assert.AreEqual(fatherReference.CollectionName, refetchedChild.FatherReference.CollectionName);
    }
}

That’s it for now. More to come. I will now focus on making it run with the latest version of MongoDB, enabling Safemode and to simplify the use of Entitystore.

//Daniel

Simple-MongoDB – Current status

So, I’ve been attending the Scandinavian Developer Conference, held by Iptor, this week, and therefore haven’t got the time to work on my driver. The conference was great and I’m looking forward to it next year.

The work with the driver is currently to support regular expressions. I recently updated the code to make use of the original Json.Net compiled assembly, since the tweak I made to support ObjectId, now exists in the main branch. The problem now is that RegEx, doesn’t seem to be supported in the BsonWriter in the lib, so I guess I have to tweak it again until it reaches the mainbranch. That’s why it takes some time.

After that I will start working on handling errors reported from the server, as well as querying.

//Daniel

Simple-MongoDB – Simplified storage of entities

New features

Just checkedin some new features to my C# 4.0 based MongoDB driver:

  • New simplified API, using generics and adds pluralization for collection
  • Added SimoIoC which will resolve resources like pluralizer, commands etc. this lets you replace certain parts of the implementation with own implementations.
  • Support for document references via the new type SimoReference

All code is written for .Net 4.0 and is tested against MongoDB v.1.2.4

All of the examples shown here can be found in the Test-projects, and most of them in the class “ApiExamples” (no I don’t generally comment my tests as I have done in this class).

The code can be found here: http://code.google.com/p/simple-mongodb/

Ok, but why Simple-MongoDB?

Before showing you the code for these new features, I thought that I should take some time to explain why I develope Simple-MongoDB when there’s good alternatives, both Sam Corder and Rob Conery & CO have their versions and it doesn’t stop there.

So, I started writing it beacause I wanted to learn more about MongoDB and because I didn’t like the tight coupling to a certain Document-type that Sam had in his driver. I wanted a driver that accepted everything seamlessly. I driver where I could use plain static types (e.g. Person-class) as well as anonymous types and Json-strings. And I don’t want the user to be writing one single line of mapping code. Thats why Simple-MongoDB.

New simplified API – Using generics with an existing model

If you do have a model built in C# code you would probably feel most comfortable with using the EntityStore-generic API. By doing this you don’t have to use strings to specify collections. Each class-type will be stored in a collection with the same name as the type, but pluralized. If you don’t want yo use pluralization, you can turn it off either by calling session.Pluralizer.Disable() or by replacing the implementation of the SimoIoC.Instance.PluralizerFactory.

The hierarchy in MongoDB is:

- Db
  - Collection
    - Document

By using EntityStore this is somewhat abstracted away.

[TestMethod]
public void Insert_Example()
{
    //You do need a connection to create a session
    //The creating of Connections and Session is something you most likely
    //will put in a IoC-container or factory or something.
    var cn = CreateConnection();
    using (var session = new SimoSession(cn))
    {
        var entityStore = new SimoEntityStore(session, DbName);

        //If you are dealing with typed documents (e.g. Person)
        //you can use the generic API.
        //Then the name of the collection is the name of the
        //type, but pluralized.
        //If you don't want pluralization, call
        //session.SimoPluralizer.Disable(), or
        //replace the implementation of the 
        //SimoIoC.Instance.PluralizerFactory
        var person = new Person { Name = "Daniel", Age = 29 };
        entityStore.Insert(person);

        //If you are using non-typed documents you have to pass
        //the entityname string to the method you are using.
        var anonymousPerson = new { Name = "Daniel" };
        entityStore.Insert("Person", anonymousPerson);

        //So the EntityStore only allows for an abstraction
        //over the Db, Collection and Document hierarchy
        //and you can of course access these to.
        var db = session[DbName];
        var persons = db["Person"];
        persons.Insert(anonymousPerson);

        //The EntityStore also holds the Database that it wraps.
        //Of course you can obtain a collection using generics against the
        //database.
        var persons2 = entityStore.Database.GetCollection<Person>();
        persons2.Insert(person);

        var numOfStoredDocuments = entityStore.Count<Person>();
        Assert.AreEqual(4, numOfStoredDocuments);
    }
}

Document references

I will let the code speak for itself.

[TestMethod]
public void ParentChildReference_Example()
{
    var cn = CreateConnection();
    using (var session = new SimoSession(cn))
    {
        var entityStore = new SimoEntityStore(session, DbName);

        //The parent generates a new _id when created.
        //That _id is then used in the reference which is attached to the child.
        //After that, you just store the items.
        var parent = new Parent { Name = "Daniel" };
        var fatherReference = entityStore.Reference<Parent>(parent._id);
        var child = new Child { Name = "Isabell", Father = fatherReference };

        //You could of course have created the reference manually, but then you loose the
        //use of the pluralizer, and have to role-this on your own.
        //new SimoReference { CollectionName = "Parents", Id = parent._id };

        entityStore.Insert(parent);
        entityStore.Insert(child);

        var refetchedChild = entityStore.FindOne<Child>(new { child._id });

        Assert.AreEqual(fatherReference.Id, refetchedChild.Father.Id);
        Assert.AreEqual(fatherReference.CollectionName, refetchedChild.Father.CollectionName);
    }
}

If you’re not working with the EntityStore but instead with the SimoCollections directly, it would look something like this (from “ParentChildTests”):

[TestMethod]
public void NewRelation_UsingAnonymousTypes_ReferenceCreated()
{
    var parentId = SimoId.NewId();
    var parent = new { _id = parentId, Name = "Daniel" };
    var fatherReference = new SimoReference
    {
        CollectionName = "Parents",
        Id = parent._id
    };
    var child = new { _id = SimoId.NewId(), Name = "Isabell", Father = fatherReference };
    InsertDocuments("Parents", parent);
    InsertDocuments("Childs", child);

    var refetchedChild = GetDocument(new { child._id }, child, "Childs");

    Assert.AreEqual(fatherReference.Id, refetchedChild.Father.Id);
    Assert.AreEqual(fatherReference.CollectionName, refetchedChild.Father.CollectionName);
}

Session factory

So there’s a verry simple SessionFactory inplace, but you can of course make one of your own or let an IoC like StructureMap resolve the sessions.

[TestMethod]
public void SessionFactory_Example()
{
    var sessionFactory = new SimoSessionFactory();
    using (var session = sessionFactory.GetSession(Constants.ConnectionStringName))
    {
        session[DbName].DropDatabase();
    }
}

Pluralization

The Pluralizer is created per Session and is enabled by default. You can of course disable it, and you can constrol how certain values are pluralized. If you want to provide a own implementation you have to adjust this via SimoEngine.IoC.PluralizerFactory.

[TestMethod]
public void DisablePluralizer_Example()
{
    var cn = CreateConnection();
    using (var session = new SimoSession(cn))
    {
        //Just call Disable on the Pluralizer
        //When you want to enable it again, call
        //Enable().
        var entityStore = new SimoEntityStore(session, DbName);
        entityStore.Session.Pluralizer.Disable();

        var person = new Person { Name = "Daniel" };
        entityStore.Insert(person);

        var refetched = entityStore.Database["Person"].FindOne<Person>(new { person.Name });

        Assert.IsNotNull(refetched);
    }
}

You can adjust how certain values should be pluralized.

[TestMethod]
public void AdjustPluralization_IsCustomPluralized()
{
    var pluralizer = new SimoPluralizer();

    pluralizer.AdjustPluralization("Monkey", "Test");

    Assert.AreEqual("Test", pluralizer.Pluralize("Monkey"));
}

That’s it for now. Not sure what I will look into next.

//Daniel