Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Persisting dynamic object in DynamoDB with .NET SDK

I'm trying to persist the following class to DynamoDB using the .NET SDK:

public class MyClass
{
    public string Id { get; set; }

    public string Name { get; set; }

    public object Settings { get; set; }
}

The problem is with the Settings property. It can be any type of object, and I do not know in advance what might be assigned to it. When I try to persist it to DynamoDB, I get the following exception:

System.InvalidOperationException: 'Type System.Object is unsupported, it has no supported members'

Both the Document Model and Object Persistence Model methods result in the same exception.

Is there a way to persist these objects in DynamoDB? Other databases like MongoDB and Azure DocumentDB will do this without any issue, and they can be deserialized to either the proper type with a discriminator, or as a dynamic JSON object.

like image 426
Carvellis Avatar asked Mar 12 '17 13:03

Carvellis


2 Answers

You can use the general approach documented here: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBContext.ArbitraryDataMapping.html

Here's my implementation for any arbitrary object:

public class DataConverter : IPropertyConverter
{
    public object FromEntry(DynamoDBEntry entry)
    {
        var primitive = entry as Primitive;
        if (primitive == null || !(primitive.Value is String) || string.IsNullOrEmpty((string)primitive.Value))
            throw new ArgumentOutOfRangeException();
        object ret = JsonConvert.DeserializeObject(primitive.Value as string);
        return ret;
    }

    public DynamoDBEntry ToEntry(object value)
    {
        var jsonString = JsonConvert.SerializeObject(value);
        DynamoDBEntry ret = new Primitive(jsonString);
        return ret;
    }
}

Then annotate your property like this:

[DynamoDBProperty(typeof(DataConverter))]
public object data { get; set; }
like image 182
JohnOpincar Avatar answered Nov 19 '22 12:11

JohnOpincar


Little improvement to the previous answer: make converter generic so that you can deserialize to the correct type, like this:

public class SerializeConverter<T> : IPropertyConverter
{
    public object FromEntry(DynamoDBEntry entry)
    {
        var primitive = entry as Primitive;
        if (primitive is not { Value: string value } || string.IsNullOrEmpty(value))
            throw new ArgumentException("Data has no value", nameof(entry));
        return JsonConvert.DeserializeObject<T>(value);
    }

    public DynamoDBEntry ToEntry(object value) => 
        new Primitive(JsonConvert.SerializeObject(value));
}

Usage:

[DynamoDBProperty(typeof(SerializeConverter<YourType>))]
public YourType data{ get; set; }
like image 1
zxsanny Avatar answered Nov 19 '22 11:11

zxsanny