Chit Khine Chit Khine - 1 month ago 24
C# Question

How to store a data from child class in DocumentDB?

I have a parent class

public class Items{
public Type FeedType { get; set; }
public double Rating { get; set; }
}


I have two subclasses of this Items

public class SingleItemResponse : Items
{
public string Id { get; set; }
}
public class MultipletemResponse : Items
{
public IEnumerable<string> Ids { get; set; }
}


I have added a list of SingleItemResponses and MultipleItemResponses to the List of Items.

var list = new List<ItemResponse>();
list.add(single); // assume that single is a object of singleItemResponse
list.add(multiple); // assume that multiple is a object of multipleitem


I can return the list with all the attributes of singleItemResponse and multipleItemResponse. However, I would like to store and retrieve them in documentDB. The problem is when I try to store them in DocumentDB as IList, they don't keep the values from Single and MultipleFeedItems, in this case it is an ID or Ids.

I would like to know how can I save and retrieve them, the only solution I have right now is to add them together in that ItemResponse but I would like to know if there is a better way without stuffing things.

Answer

Method 1. Persist json hierarchy

In case of retrieving, if two derivated objects have distinguishable properties like Id and Ids, you can compare it in JObject first and then create to your types.

string collectionName = "YourCollectionName";
Guid id = Guid.Parse("275319a3-d395-46f2-9370-f3eadf691e03"); // Manually set GUID for test purpose.

Uri documentUri = UriFactory.CreateDocumentUri(DocumentDbDatabaseNameConfig, collectionName, id.ToString());
Uri collectionUri = UriFactory.CreateDocumentCollectionUri(DocumentDbDatabaseNameConfig, collectionName);

// test variables.
var list = new List<Items>();
list.Add(new SingleItemResponse() { Rating = 2.2d, Id = "id" });
list.Add(new MultipletemResponse() { Rating = 2.2d, Ids = new List<string>() { "ids1", "ids2"}});

JObject jInput = new JObject();
jInput.Add("id", id);
jInput.Add("list", JArray.FromObject(list));

// Store data.
var upsertedResult = _documentDbclient.UpsertDocumentAsync(collectionUri, jInput, null, true).Result;

// Read stored data.
var result = _documentDbclient.ReadDocumentAsync(documentUri).Result;

JObject jResult = (dynamic)result.Resource;

JArray jArray = (JArray) jResult["list"];
foreach (var jElement in jArray)
{
    if (jElement["Id"] != null)
    {
        SingleItemResponse single = (SingleItemResponse)jElement.ToObject(typeof(SingleItemResponse));
        // Do your job with single instance.
    }
    else if (jElement["Ids"] != null)
    {
        MultipletemResponse multiple = (MultipletemResponse)jElement.ToObject(typeof(MultipletemResponse));
        // Do your job with multiple instance.
    }
}

In addition, inserted data is as below;

{
  "id": "275319a3-d395-46f2-9370-f3eadf691e03",
  "list": [
    {
      "Id": "id",
      "Rating": 2.2
    },
    {
      "Ids": [
        "ids1",
        "ids2"
      ],
      "Rating": 2.2
    }
  ],
  "_rid": "KywuAN7aNQABAAAAAAAAAA==",
  "_self": "dbs/KywuAA==/colls/KywuAN7aNQA=/docs/KywuAN7aNQABAAAAAAAAAA==/",
  "_etag": "\"0000ee05-0000-0000-0000-57ff9ecb0000\"",
  "_attachments": "attachments/",
  "_ts": 1476370121
}

Method 2. Crunch into inline json serialized string

This method got a hint from this post. In my experience, I cannot make correct serialized result that contains its own type in each items. But in theory, it could work.

JObject jInput = new JObject();

// Use custom serialize/deserialize setting.
JsonSerializerSettings settings = new JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.Auto
};

JArray jArray = JArray.FromObject(list);
string strJson = JsonConvert.SerializeObject(jArray, settings);

jInput.Add("id", id);
jInput.Add("strJson", strJson); // treat json just like strings.

var upsertedResult = _documentDbclient.UpsertDocumentAsync(collectionUri, jInput, null, true).Result;

var result = _documentDbclient.ReadDocumentAsync(documentUri).Result;
JObject jResult = (dynamic)result.Resource;
jResult.ToString().Dump();

List<Items> obj = JsonConvert.DeserializeObject<List<Items>>(jResult["strJson"].Value<string>(), settings);