Chris Marisic
Chris Marisic

Reputation: 33098

Using ServiceStack OrmLite to create Key Value table for dynamic types

I want to create a key value table in my database along the lines of

public class KeyValue { 
    public string Id { get; set; }
    public dynamic Value {get; set; }
}

Using a slightly modified SqlProvider I have no problems getting CreateTable<KeyValue>() to generate varchar(1024) Id, varchar(max) Value.

I have no issues saving objects to it. The problem is when I load the objects

var content = dbConn.GetById<KeyValue>("about");

content.Value at this point is a string.

Looking at the database record, the text for value does not appear to store any type information.

Is there really anything I can do better other than manually invoking ServiceStack.Text and call deserialize with the appropriate type information?

I do not need absolute dynamic, my actual use case is for polymorphism with a base class instead of dynamic. So I don't really care what type Value is whether it's the base class, dynamic, object, etc. Regardless other than using the class

public class KeyValue { 
    public string Id { get; set; }
    public MySpecificChildType Value {get; set; }
}

I haven't been able to get anything other than a string back for Value. Can I tell OrmLite to serialize the type information to be able to correctly deserialize my objects or do I just have to do it manually?

Edit: some further information. OrmLite is using the Jsv serializer defined by ServiceStack.Text.TypeSerializer and is in no way pluggable in the BSD version. If I add a Type property to my KeyValue class with the dynamic Value I can do

var value = content.Value as string;
MySpecificChildType strongType = 
                TypeSerializer.DeserializeFromString(content, content.Type);

I just really want a better way to do this, I really don't like an object of 1 type going into the db coming back out with a different type (string).

Upvotes: 1

Views: 512

Answers (1)

Hyddan
Hyddan

Reputation: 1337

I haven't worked much with the JsvSerializer but with the JsonSerializer you can achieve this (in a few different ways) and as of ServiceStack 4.0.11 you can opt to use the JsonSerializer instead, see https://github.com/ServiceStack/ServiceStack/blob/master/release-notes.md#v4011-release-notes.

Example

public abstract class BaseClass {
    //Used for second example of custom type lookup
    public abstract string Type { get; set; }
}

public class ChildA : BaseClass {
    //Used for second example of custom type lookup
    public override string Type { get; set; }

    public string PropA { get; set; }
}

And then in your init/bootstrap class you can configure the serializer to emit the type information needed for proper deserialization:

public class Bootstrapper {
    public void Init() {
        ServiceStack.Text.JsConfig.ExcludeTypeInfo = false;
        ServiceStack.Text.JsConfig.IncludeTypeInfo = true;
    }
}

If you wish to use something other that the default "__type" attribute that ServiceStack uses (if you for example want to have a friendly name identifying the type rather then namespace/assembly) you can also configure your own custom type lookup as such

public class Bootstrapper {
    public void Init() {
        ServiceStack.Text.JsConfig.ExcludeTypeInfo = false;
        ServiceStack.Text.JsConfig.IncludeTypeInfo = true;

        ServiceStack.Text.JsConfig.TypeAttr = "type";
        ServiceStack.Text.JsConfig.TypeFinder = type =>
        {
            if ("CustomTypeName".Equals(type, StringComparison.OrdinalIgnoreCase))
            {
                return typeof(ChildA);
            }

            return typeof(BaseClass);
        }
    }
}

Upvotes: 2

Related Questions