For anyone that wished they could use MongoDB in their project, but wanted to still offer customers the ability to use their favorite Mindscape provider, or mix the 2 database types, here's how.
Its really simple actually.
I have attatched a full working example with source code, and instructions on how to try it out.
Do try it, there are some awesome things about MongoDB, and some less nice things, but it IS better suited to certain situationas than traditional relational databases. Take a loook at what iv done, and enjoy the power of both models :)
The preperation work will only take 15 minutes (once off), and from there on you will be able to use MongoDB with very little extra work required using Lightspeed (or seamlessly switching databases).
It's actually VERY simple and wont take you long.
Pre-reqisites to get this sample running (or any MongoDB project).
=========================================
1. Download MongoDb from http://www.mongodb.org/downloads
2. Download NoRM (.Net and mono driver dor MongoDB) from https://github.com/atheken/NoRM
3. You will need the Source code version of Lightspeed (2 small changes are required in the source code)
Steps to perform before you can start
=====================================
MongoDB:
========
1. Unzip folder to a folder of your choice
2. Make the following directory on your computer C:\data\db (All mongoDB data is stored here)
3. Simply run the mongod.exe to use MongoDB, no setup, no configuration needed.
NoRM
====
1. You need to sign the assembly (we use it in the lightspeed, and need it signed)
2. Open the solution, go to properties, and check the "sign the assembly" checkbox
3. Compile release version, you might get 1 error, something to do with it being referenced by the NoRM.tests solution, simply delete thae offending line dispayed as an error.
LightSpeed
==========
1. Open the Lightspeed solution (LightSpeed-core.sln), and add the NoRM .dll as a referenced .Dll to the Framework project
2. Open EntityT.cs and go to the property "public TId Id" and add the setter set { _id = value; },
this will allow you to change the entity Id from within your source code. MongoDb(NoRM) needs to set the Id during de-serialization or it will crash,
and I like it too (When using Mongo, I set the Id in the constructor of the Class), that way I build up the complete DOM in memory and dont have to wait for the results to come back from the DB to set references,
they are always correct.
3. Open Entity.cs and add the following attribute to all properties [Norm.Attributes.MongoIgnore]
I'm not sure which ones need to be changed (perhaps only 1 of them :P) Somewhere here MongoDB sees a circular reference, and we are just making sure that all these properties are ignored by MongoDB (NoRM)
4. Make sure you use these .Dll's in your projecvt and not the ones that come with Lightspeed and NoRM
Notes:
======
1. NoRM writes all Properties to the Database (serialize/Deserialize) so add [Norm.Attributes.MongoIgnore] to all properties that you dont wish to have as part of your database Object
For example you might wish to have an object written to MongoDB, but not the related field from another table (as it is a seperate object),
simply use this attribute in your designer on the reference to ensure it does not get written as part of that object.
2. Lightspeed Uses fields, so Add [Transient] to all fields you add yourself and dont wish to be part of the Lightspeed model.
3. Make sure you use the attribute Norm.Attributes.MongoIgnore to all Back references in your Lightspeed model. (Or NoRM will have a circular reference)
If you dont do this NoRM will crash with an infinite loop on serialization to MongoDB.
4. I used the Norm.Attributes.MongoIgnore reference on the 2 relationships back references (Language->LanguageItems) and (Family->Person)
This is the only thing I had to do in the designer to make it "MongoDB" compatible
What do I do to get it working (Idea behind what I'm doing)
===========================================================
1. When Using Lightspeed, I use vanilla Lightspeed without changes.
2. when Using MongoDB, I bypass the Lightspeed UnitofWork completely.
3. I Achieve this by creating a Connection factory that creates a Lightspeed or MongoDB connection and reference them via the interface.
4. All classes are Lightspeed entities and I can switch database by simply changing 1 setting in the app.config, or even read/write data from mongo, and Lightspeed seamlessly,
storing data that is better suited to the relevant DB in the place it belongs.
5. Guid as Id for all classes MongoDB uses a Guid or ObjectId that does not work in other Databases without a converter. So use a Guid for all your classes ID's.
Performance
===========
Adding a few simple lookup lists, etc MongoDB was 25 times faster than SQLServer at adding simple lists
Reading them all back (I cache them in my app) MongoDB was 5 times faster than SQLServer2008.
This obviously fluctuates, but it gives you an idea of the massive performance increase.
The more complex your data object is the greater the performance increase of MongoDB becomes.
MongoDB is perfectly suited to a lot of inserts or working with comples objects that get read/writtem as a single object.
Think of a persons pensioen, you have "snapshots" of the persion situation during time, the snapshot consists of his partners, children, pensioen rules,
and various calculated / value fields in a relationship model about 10 tables. You always read the entire snapshot in, never only a part of it. MongoDB is perfect for this.
It also works on linux!!
Disadvantages: MongoDB retrieves an entire object from the database, you cant retrieve only a few fields from it, and link them to another object.
It is designed to work on objects, not related data or fields in an object. Loose SQLQueries are useless here.. Remember this in your design.
More advanced ideas in the sample.
==================================
A Person has a Hobby, and in a related database you would use a foreign Key.
But MongoDB does not have relationships.
1. One way to implement this relationship is in code, DONT link the tables with a foreign key in the designer, but write a property on the Person class to retrieve the Hobby, this works for both models.
2. Another way to implement this would be to use a foreign key in the designer, and then you would have to load the Hobby object into the persons Hobby reference after loading the person.
To make this work you would have to use the Norm.Attributes.MongoIgnore attribute on the back reference and collection attributes, this would make MongoDB ignore the relation completely.
I'm going to implement the first option in this sample. Look at the Person class to see the implementation