Search code examples
c#serializationservicestackormlite-servicestackservicestack-text

ServiceStack ormlite json does not deserialize from database


ServiceStack ORMLite does not deserialize my class from Postgresql.

Keeping the objects on cache solves, but it can't load them back (saving is ok).

Below is a code that reproduces the problem.

void Main()
{
    var inv = new Inventory();
    inv.Items.Add(new Item{Id=1,CreatedAt=DateTime.Now, Key="potion10", Descriptions=new Dictionary<int, string>{{1,"Poção que recupera um pouco de vida."},{2,"Potion that restores a little of health."}}, HealthModifier=10,IsUseable=true, Names=new Dictionary<int, string>{{1,"Poção Leve"},{2,"Minor Potion"}}, UpdatedAt=DateTime.Now}, 2);

    var invJson = inv.ToJson().To<Inventory>(); // can't deserialize
    var invJsv = inv.ToJsv().To<Inventory>(); // same problem
}

public class Item
{
    public Item()
    {
        Names = new Dictionary<int, string>();
        Descriptions = new Dictionary<int, string>();
    }

    public long Id { get; set; }

    public string Key { get; set; }

    public Dictionary<int, string> Names { get; set; }

    public Dictionary<int, string> Descriptions { get; set; }

    public int HealthModifier { get; set; }

    public bool IsUseable { get; set; }

    public DateTime CreatedAt { get; set; }

    public DateTime UpdatedAt { get; set; }
}

public class Inventory
{
    public Inventory()
    {
        Items = new Dictionary<Item, int>();
    }

    public Dictionary<Item, int> Items { get; set; }
}

The JSON on Postgresql is the same from the code above.

{
    "Items":{
        "{"Id":1,
        "Key":"potion10",
        "Names":{
            "1":"Poção Leve",
            "2":"Minor Potion"
        },
        "Descriptions":{
            "1":"Poção que recupera um pouco de vida.",
            "2":"Potion that restores a little of health."
        },
        "HealthModifier":10,
        "IsUseable":true,
        "CreatedAt":"\/Date(1430743156138-0300)\/",
        "UpdatedAt":"\/Date(1430743156139-0300)\/"
    }:2
}
}

Solution

  • The problem is that your class Inventory has a dictionary keyed by a complex class:

    public Dictionary<Item, int> Items { get; set; }
    

    However, according to the ServiceStack.Text documentation

    Any IDictionary is serialized into a standard JSON object, i.e:

         {"A":1,"B":2,"C":3,"D":4}
    

    Unfortunately your Item class cannot be represented as a simple string thus cannot be used as a JSON property name.

    What you could do is to serialize your items as an array of key-value pairs. Since the ServiceStack Text serializers support [DataMember] aliases and also support ignoring of data members, you can do the following:

    [DataContract]
    public class Inventory
    {
        public Inventory()
        {
            Items = new Dictionary<Item, int>();
        }
    
        [IgnoreDataMember]
        public Dictionary<Item, int> Items { get; set; }
    
        [DataMember(Name = "Items")]
        public KeyValuePair<Item, int> [] ItemArray
        {
            get
            {
                return Items == null ? null : Items.ToArray();
            }
            set
            {
                (Items ?? (Items = new Dictionary<Item, int>())).Clear();
                if (value != null)
                    foreach (var pair in value)
                        Items[pair.Key] = pair.Value;
            }
        }
    }
    

    This will serialize and deserialize valid JSON that should look something like this:

    {
      "Items": [
        {
          "Key": {
            "Id": 1,
            "Key": "potion10",
            "Names": {
              "1": "Poção Leve",
              "2": "Minor Potion"
            },
            "Descriptions": {
              "1": "Poção que recupera um pouco de vida.",
              "2": "Potion that restores a little of health."
            },
            "HealthModifier": 10,
            "IsUseable": true,
            "CreatedAt": "2015-05-04T02:07:10.7216263-04:00",
            "UpdatedAt": "2015-05-04T02:07:10.7216263-04:00"
          },
          "Value": 2
        }
      ]
    }
    

    However, you mentioned that your JSON was coming from Postgresql. What does that JSON look like? You may need to adapt your serialization or classes to what you are actually receiving.