17

I'm seeing some weird behavior saving to DocumentDB. I started out saving documents using a plain old class that looked like this:

public class Person
{
    public string Name;
    public int Age;
}

I saved these documents like this:

var person = new Person { ... };
client.CreateDocumentAsync(myCollectionLink, person);

This worked fine. Properties were saved with exactly the names in the class. Then I realized I needed the document's SelfLink in order to perform updates and deletes. "Ah," I thought. "I'll just derive from Document, like so:

public class Person: Microsoft.Azure.Documents.Document
{
    public string Name;
    public int Age;
}

However, much to my surprise, when I made this change, new documents were created completely blank, except for the "id" property assigned by DocumentDB itself.

I double-checked multiple times. Deriving from Document prevents my custom properties in the document from being saved...

...unless I explicitly decorate each one with [JsonProperty], like so:

public class Person: Document
{
    [JsonProperty(PropertyName="name")]
    public string Name;

    [JsonProperty(PropertyName="age")]
    public int Age;
}

Then it works again (using, of course, the new more JSON-appropriate camelCase property names). And, upon retrieval, the objects get populated with the SelfLink property that I need for updates and deletes. All good.

By my questions are...Why did this happen? Am I doing something wrong by deriving from Document? Your feedback would be much appreciated.

abatishchev
  • 98,240
  • 88
  • 296
  • 433
Brian Rak
  • 4,912
  • 6
  • 34
  • 44

1 Answers1

25

This behavior is attributed to how JSON.NET deals with properties on dynamic objects. It effectively ignores them unless you decorate them with the JsonProperty attribute.

You can either work with plain POCO or you can extend from Resource (shown below), which is a static object that Document itself extends.

public class Person: Microsoft.Azure.Documents.Resource
{
    public string Name;
    public int Age;
}
Aravind Krishna R.
  • 7,885
  • 27
  • 37
Ryan CrawCour
  • 2,704
  • 1
  • 19
  • 25
  • 1
    Thanks, Ryan! That does indeed work better. One followup question -- is one particular approach (Document + attributes vs Resource) preferred as a best practice? – Brian Rak May 07 '15 at 16:03
  • 4
    Totally saved me. I could not find ANY documentation like this for the life of me. Thank you – Ryan Bennett Aug 25 '15 at 21:50
  • Glad I saw this, I've been pulling my hair out for an hr trying to figure out why inheriting from Document wasn't working. – James Alexander Aug 31 '15 at 21:47
  • 2
    Is there any documentation on using plain POCOs inheriting from Resource or using dynamic objects and/or pros cons etc? – Mark Redman Oct 03 '17 at 06:18
  • 2
    We have been using POCOs for the longest time with DocDb, and wanted to start leveraging _ts and _etag, so we extended Document (probably from an example or SO answer). We saw some really nasty behavior due to the Dynamic nature of Document (duplicate keys in the serialized JSON, for example). Here are some docs that say extending Resource isn't a bad idea: https://learn.microsoft.com/en-us/dotnet/api/microsoft.azure.documents.client.documentclient.createdocumentasync?view=azure-dotnet – Jacob McKay Mar 30 '18 at 16:53
  • 1
    Duplicate keys in the serialized JSON is what brought me to this answer and no, I hadn't found it anywhere else either. The other side effect I'll note here (for future searchers) is that if you select a single doc by ID and serialize to a POCO inheriting from Document, all is well. But if you return a collection, each single item includes the dynamic attributes which cause the duplicate serialization. If you try to update one of those, the updated value doesn't commit AND it causes the index for it to fail. Switching the base to "Resource" solved all of that. – Brett Nov 04 '18 at 19:24