How do I store a complete object in Couchbase (beginner) C#


#1

Hi,

perhaps I just didn’t understand it completely from the Documentation, but is it correct, that I only can store Dictionaries in Couchbase.Lite? How do I convert a complex object into a dictionary.
Normally I would use JSON.net to serialize my Objects to JSON, but I didn’t find a function in Couchbase to store a JSON String into Couchbase.

The same goes the other way round, how to retrieve Objects from Couchbase.

Please help me getting started.

Thomas


#2

It’s not an automatic process. Your program will need to implement this logic. Think of your object like one big dictionary, where each property or field is a key with a value and create your dictionary based on that. If you have ever used NSCoding in Objective-C and ISerializable in C# it is a similar idea.


#3

Ok, I got this, but I don’t understand why I have to go this way. JSON.net let me serialize my Objects to JSON without any problems. Why can’t I store them then in couchbase? If I understand it right Couchbase.Lite already uses JSON.net. Why doesn’t it have functions to directly store c# objects?

Are you seroius that I have to write a custom “ToDictionary converter” for each of my classes?


#4

Im’ not sure if this solution is the correct one, but it seems to work and is pretty easy:

I have this class

public class TestClass
{
    public string TestString;
    public string TestStringProperty { get; set; }
    public DateTime TestDate;
    public List<string> TestStringList;
}

That I want so store and retrieve I tried this here and it seems to work fine. I just put the Object I want to store inbto the Property dictionary:

        var c = new TestClass() {TestString = "SimpleStringfield", TestDate = DateTime.Today,TestStringProperty = "TestStringPropertyContent",
                                  TestStringList = new List<string>(new string[] { "item1","item2","item3"})};


	    var manager = Manager.SharedInstance;
	    var db = manager.GetDatabase("test_database");
	    if (db == null)
	    {
	        System.Diagnostics.Debug.WriteLine("--------------------------Could not open Database");
	    }
      var doc = db.CreateDocument();
        var properties = new Dictionary<string,Object>() { {"type","day"}, {"day",c} };
      var rev = doc.PutProperties(properties);
      var docread = db.GetDocument(doc.Id);
      JObject testobject = (JObject)docread.GetProperty("day");
      var o = testobject.ToObject<TestClass>();

Is this the right way?


Couchbase Lite .Net object models
#5

I will always assert that the “right way” is the way that works. The fact that the library uses JSON .NET internally is an implementation detail, though. If that were to change for some reason then this way would break. I also have a feeling that if the class were more complex than your example than it would break as well. We are currently designing a cross platform specification to do just what you want to do (save classes directly to the database without converting to a dictionary first). This will be a slow process though because there is a lot of thought that needs to go into it (not just for C#, but for Java and Objective-C as well). For example, how to serialize a class that has a property which references back to it, etc. I know JSON .NET already does this, but I don’t want to start exposing JSON .NET into the public API because eventually it should be switchable (in case JSON .NET does not work for whatever reason on a platform).


#6

Hi Jim,
but you would agree that there is an assymetrie in the current state. I’m allowed to put any object into the Dictionary and it does get serialized, but don’t get them back in their original state.

I understand your point that you don’t want to expose JSON.NET, but why not offer functions like:

StoreObject(string objectType, string id, Object object)

and

Object GetObject(string id, Type typeOfObject)

which internally use JSON.net without exposing them. And forbidd reference ciycles?
I have used JSON.net with complex objects in the past and it worked really well.


#7

I actually wasn’t aware of anyone trying to put custom objects into the database until now. I guess I could forbid this behavior until we have something better, but I cannot simply add public API without the approval of our architect and a plan of action on how to tackle it well between the three versions of the library. As I said, we are working on an API similar to the one you mentioned but unfortunately it will not be ready for a while.


#8

No problem, I currently work on my own Wrapper Component. Please don’t forbid it for the moment. As soon as You have the new API, I will then port my Wrapper to it.
If it works well, I might put my Wrapper on gitHub. Perhaps you can get some inspiration from it.


#9

@borrrden - I have similar needs as @escamoteur. I have way too many different types of objects for it to be efficient to manually maintain code to go to and from dictionaries for all of them.

Is it possible to just pass in a string of json that contains the data of all my user properties that I want to save? That way I can use JSON.net (or whatever) configured how I need to it be (for example, I need it to be able to handle NodaTime types) in order to create/parse the json myself.

In other words, it would be great I could use Couchbase.net library to handle the interaction with the underlying data store and allow me to get raw json in and out. No need for dictionaries.

Is this possible today?

I found a pretty simple solution that appears to work in my tests so far however it isn’t as efficient as I’d like. Basically, JSON.net can be used to convert from a Dictionary<string, object> to my custom class and vice versa. When I get a dictionary, I convert it to json (using JSON.net directly) and then deserialize it to the class I actually want (also using JSON.net). This avoids any issues with sometimes encountering JArray or needing to implement custom handling for saving/parsing things like DateTimeOffset. Here are the two key methods:

public static Dictionary<string, object> ToCouchDictionary(object obj)
{
	// Experimental
	var json = JsonConvert.SerializeObject(obj);
	var jsonToDict = JsonConvert.DeserializeObject<Dictionary<string, object>> (json);	
	return jsonToDict;
}

public static TObj ToObject<TObj>(IDictionary<string, object> dict)
{
	// Experimental
	var json = JsonConvert.SerializeObject(dict);
	var obj = JsonConvert.DeserializeObject<TObj> (json);
	return obj;
}

Does anyone see any limitations/drawbacks with this approach? I think its inefficient since I’m adding extra serialization & deserialization steps every time. Ideally I think I would like to have the option of just getting/setting the raw json user properties.

I would appreciate any of your thoughts on this.


C# How to serialize/deserialize an Object to/from Dictionary<string,Object> to save/load it in Couchbase.lite
#10

Yes I agree this is needed but it is unlikely to come in 1.x. We are all hard at work on redesigning things to be way more awesome for 2.0 (that’s quite a ways in the future though…probably half a year). For the time being, I suppose you could store a dictionary with one key, and the value being your json, inside the DB.


#11

You can do whatever you want that provides the right dictionary. If you want to generate JSON and then parse that into a Dictionary, go ahead. It’ll be a little more expensive, but hopefully not too much.

I’m leery of the idea of exposing JSON data directly in the API. For one thing, I would like to move away from using JSON as the internal storage type in the database; it’s expensive to parse and generate. There are a number of more efficient binary formats with the same semantics. But we should of course keep this as an implementation detail and not expose it, which implies not letting the client app see the raw data format, only parsed data.


Accessing CouchbaseLite document JSON