SisoDb – An early prototype

A while back ago I started to fiddle with the CTP of code first in Entity framework 4. The product is great but I wanted something else, I wanted something “more” schemaless. I turned to MongoDB and wrote together an open source driver targeting .Net 4. Still, there was things that I didn’t like so I built a document DB over Lucene. Ayende Rahien has also done this and he has a creat solution called Raven DB. I relatively quickly discovered that I missed all the great infrastructure that SQL-server provides. Security, tables for the DBA’s, replication, scheduler etc, so I prototyped a solution that uses JSON to create a document/structure DB over SQL-server, namely: Simple Structure Oriented Db (SisoDb). Note the word prototype here. I will make changes to it and I still need to build a nice querying solution, preferably using Linq.

How does it work

SisoDb stores your POCO-graphs (plain old clr objects) using JSON which enables us to go from a POCO to persistable JSON. For each entity there will be two tables (tables are created on the fly). One holds the Id of the entity and the Json-representation. The second table holds a key-value representation of each indexed property of the entity. If an entity contains complex types (custom classes) the scalar properties of these custom classes will be stored and indexed to. All scalar properties are stored as strings in the invariant-culture representation. Remember that the complete graph is serialized and deserialized so there’s no magical lazy loading and stuff, instead you have to think a bit before designing deep graphs.

Hey, wait! It sound like duplicate data is stored.

Yes, that’s correct. The complete graph of the entity is stored as JSON as well as in the second table (the index table) as key-values. This is done to get a more query friendly representation of the entity. You will be able to exclude properties from being indexed, but right now everything is indexed.

JSON, hmmm. How do I handle schema changes?

Well if you keep your self to the open-closed principle and just add new properties nothing is needed, it all works. You also don’t have to do anything if you drop properties, the JSON-serialization process will handle this for you. Since I use the well know JSON-framework by Newtonsoft (http://json.codeplex.com/), you can of course affect the serialization by injecting custom converters etc.

Pure POCOS, really?

Yes. No proxies or base-classes or interfaces. The only thing that is currently needed is one property:

public Guid Id { get; set; }

This is used to keep track of the entity and that is all that is needed.

Show me some code

The first step is of course to have an entity to persist. I will use a Customer that has scalar properties as well as complex-proprties of type Address.

The model

[Serializable]
public class Customer
{
    public Guid Id { get; set; }
    public string Firstname { get; set; }
    public string Lastname { get; set; }
    public ShoppingIndexes ShoppingIndex { get; set; }
    public DateTime CustomerSince { get; set; }
    public Address BillingAddress { get; set; }
    public Address DeliveryAddress { get; set; }
    public Customer()
    {
        ShoppingIndex = ShoppingIndexes.Level0;
        BillingAddress = new Address();
        DeliveryAddress = new Address();
    }
}

[Serializable]
public class Address
{
    public string Street { get; set; }
    public string Zip { get; set; }
    public string City { get; set; }
    public string Country { get; set; }
    public int AreaCode { get; set; }
}

[Serializable]
public enum ShoppingIndexes
{
    Level0 = 0,
    Level1 = 10,
    Level2 = 20,
    Level3 = 30
}

Pay attention, there’s no specific interfaces or base-classes. It’s a POCO!

Structure schemas

To get a hang of things I will first show you the structure schema that is generated. Note! This is nothing you need to control. The structure schema contains accessors to the key-property and all the indexed properties. The accessors are used to get values from an instance of the entity.

var customerSchema = database.StructureSchemas.GetSchema<Customer>();

Console.Out.WriteLine("KeyAccessor.Name \t=\t {0}", customerSchema.KeyAccessor.Name);

foreach (var indexAccessor in customerSchema.IndexAccessors) 
	Console.Out.WriteLine("IndexAccessor.Name \t=\t {0}", indexAccessor.Name);


KeyAccessor.Name = Id
IndexAccessor.Name = Firstname
IndexAccessor.Name = Lastname
IndexAccessor.Name = ShoppingIndex
IndexAccessor.Name = CustomerSince
IndexAccessor.Name = BillingAddress.Street
IndexAccessor.Name = BillingAddress.Zip
IndexAccessor.Name = BillingAddress.City
IndexAccessor.Name = BillingAddress.Country
IndexAccessor.Name = BillingAddress.AreaCode
IndexAccessor.Name = DeliveryAddress.Street
IndexAccessor.Name = DeliveryAddress.Zip
IndexAccessor.Name = DeliveryAddress.City
IndexAccessor.Name = DeliveryAddress.Country
IndexAccessor.Name = DeliveryAddress.AreaCode

Again, this is nothing you have to use, tweak or manage. It’s just there and works.

Insert some data

To get stared you need a SisoConnectionInfoYou which contains the connection string. Currently there’s also a StorageProviders enumeration, but it only has one provider (since I have stripped out the Lucene provider). You also need an instance of an SisoDatabase. This should be long-lived and is preferable controlled by your IoC. After that you do transactional work by letting the SisoDatabase create an UnitOfWork-instance.

var cnInfo = new SisoConnectionInfo(
	StorageProviders.SqlProvider,
	@"Data source=localhost;
	Initial catalog=SisoDbLab;Integrated security=SSPI;");

var db = new SisoDatabase(cnInfo);
db.EnsureNewDatabase();

//... create some new customer instances...

using (var unitOfWork = database.CreateUnitOfWork())
{
    unitOfWork.InsertMany(customers);
    unitOfWork.Commit();
}

The UnitOfWork implements IDisposable so you should use it in conjuntion with an using-block. If you don’t call Commit() , a rollback will be performed.
That’s it for today. Remeber, it’s a prototype, and for the next writing (hopefully this week) I will have some query capabilities to show, but not a complete Linq-provider.

The project is hosted here: http://code.google.com/p/sisodb/

Features in the pipe

- Querying
– Provide you with the unit-tests and integration tests.
– Attribute that enables you to say “Don’t index this property in the entity”.

Features in the future

- Navigation properties
– Support for other databases

//Daniel

About these ads

9 thoughts on “SisoDb – An early prototype

  1. Pingback: DotNetKicks.com

  2. Pingback: Tweets that mention SisoDb – An early prototype « Daniel Wertheim -- Topsy.com

  3. Pingback: DotNetShoutout

  4. Pingback: Tonights update to SisoDb « Daniel Wertheim

  5. Pingback: NoSQL Daily – Wed Oct 6 › PHP App Engine

  6. Pingback: BitterCoder – 2010-10-20 – Auckland Architecture Chat Tomorrow

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s