Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Storing/Retrieving Dynamic Data in RavenDB

I'm using RavenDB & need to store dynamic data like:

public class User {
    public string Name;
    public dynamic Data;
}

It appears that I could use many different types such as dynamic, RavenJObject, DynamicJsonObject, ExpandoObject, Dictionary<string, object>, but I don't know what the differences are.

Could someone explain the options for dynamic data? I care less about querying & more about easy storage & retrieval.

like image 269
bendytree Avatar asked Apr 09 '12 03:04

bendytree


2 Answers

Problem

Here's the deal, if you have a dynamic property then RavenDB will always deserialize it as a RavenJObject. For example:

public class User {
    public dynamic Data = new ExpandoObject();
}

...

var user = new User();
user.Data.SomethingNew1 = "foo";

This looks harmless & works fine when you create your user. But when you Load user, RavenDB doesn't know what type you want for dynamic so it uses RavenJObject. You can't dynamically create properties (expando style) with RavenJObject so this fails:

var user = session.Find<User>(...);
user.Data.SomethingNew2 = "foo"; //compiles, but throws

My Solution

Use an ExpandoObject and explicitly define its type in the property that is serialized. That lets RavenDB (or JSON i guess) know what type you're expecting & it doesn't have to guess RavenJObject. Then, to keep your syntactical magic, wrap the property with a dynamic accessor.

public class User {
    public ExpandoObject _Data = new ExpandoObject();

    public dynamic Data {
        get { return _Data; }
    }
}

There are ways to make the expando object private & to create a setter for Data, but you get the idea.

More Problems

Update: Unfortunately this solution exposes more problems. Say you store a list of strings in your dynamic data:

user.Data.Keys = new List<String>{"a","b","c"};

After you serialize/deserialize, JSON/Raven again doesn't know what type you are expecting. So if you try this (see below) then it compiles but you get a runtime exception Cannot implicitly convert type 'Raven.Abstractions.Linq.DynamicList' to 'System.Collections.Generic.List':

List<string> keys = user.Data.Keys;
like image 69
bendytree Avatar answered Oct 15 '22 12:10

bendytree


For all of those, it doesn't really matter what your in memory type is.

object, dynamic and DynamicJsonObject are the same thing - as far as RavenDB is concerned. It gives you a dynamic implementation using RavenJObject as the backend for that.

RavenJObject is literally just the value that you get from the server.

ExpandoObject and Dictionary are serialized to/from dictionary, is all.

like image 27
Ayende Rahien Avatar answered Oct 15 '22 10:10

Ayende Rahien