Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I customize the serialization/deserialization of a complex type in ServiceStack.OrmLite

I am using ServiceStack.OrmLite to persist data in a SQLite database, and quite happy with it so far.

However, many of my objects have properties of a complex type which I don't want serialized using JSV.

I need to be able to specify a custom serialization/deserialization that should be used to store the property in the database (as a string). In the db4o world this would be equivalent to using the translation feature provided by IObjectConstructor.

A good example of complex types that cannot be serialized and deserialized properly are NodaTime types, even though they can be easily mapped to strings (I already have the serialization/deserialization functions which I used with db4o).

What is the simplest way to achieve that? A wrapper would not be very convenient as I would have to write and maintain one for each type that contains a property of this complex type.

like image 954
Erwin Mayer Avatar asked Nov 01 '13 02:11

Erwin Mayer


2 Answers

For those who may be interested in the wrapper pattern I am currently using to implement custom serialization with OrmLite (works with other ORMs too), here is a simple working example with NodaTime types that are otherwise not serialized properly:

public class BusinessObject {
    public class Poco {
        public readonly BusinessObject BusinessObject;

        public Poco(BusinessObject businessObject) {
            this.BusinessObject = businessObject;
        }

        public Poco() {
            this.BusinessObject = new BusinessObject();
        }

        public string Id {
            get { return this.BusinessObject.Id; }
            set { this.BusinessObject.Id = value; }
        }

        public decimal Amount {
            get { return this.BusinessObject.Amount; }
            set { this.BusinessObject.Amount = value; }
        }

        public DateTime Dt {
            get { return this.BusinessObject.Dt.ToDateTime(); }
            set { this.BusinessObject.Dt = LocalDateTime.FromDateTime(value).Date; }
        }

        public string TimeZone {
            get { return this.BusinessObject.TimeZone.Id; }
            set { this.BusinessObject.TimeZone = DateTimeZoneProviders.Tzdb.GetZoneOrNull(value); }
        }

        public string Description {
            get { return this.BusinessObject.Description; }
            set { this.BusinessObject.Description = value; }
        }
    }

    public string Id { get; private set; }
    public decimal Amount { get; private set; }
    public LocalDate Dt { get; private set; }
    public DateTimeZone TimeZone { get; private set; }
    public string Description { get; private set; }

    public BusinessObject() { }

    public BusinessObject(string id, decimal amount, LocalDate dt, DateTimeZone timeZone, string description) {
        this.Id = id;
        this.Amount = amount;
        this.Dt = dt;
        this.TimeZone = timeZone;
        this.Description = description;
    }
}

I hope it will soon be possible to define hooks/callbacks for specific types that should be handled with custom code, and also that OrmLite will allow properties with private setters to be reloaded from persistence (currently it will only work in one direction).

Update (2014/03/08): As a temporary workaround, it is possible to have OrmLite use custom serialization/deserialization by calling first:

JsConfig<BusinessObject>.TreatValueAsRefType = true;

Even if BusinessObject is a reference type. Then, you can enjoy the beauty/simplicity/ubiquity of:

JsConfig<BusinessObject>.RawSerializeFn = bo => bo.Serialize();
JsConfig<BusinessObject>.RawDeserializeFn = str => BusinessObject.Deserialize(str);

Hopefully support for custom mapping will be added soon (so that for example a NodaTime.LocalDate can be mapped to a DateTime instead of a string).

like image 143
Erwin Mayer Avatar answered Sep 29 '22 23:09

Erwin Mayer


OrmLite now supports pluggable text serializers.

Pluggable serialization lets you specify different serialization strategies of Complex Types for each available RDBMS provider, e.g:

//ServiceStack's JSON and JSV Format
SqliteDialect.Provider.StringSerializer = new JsvStringSerializer();       
PostgreSqlDialect.Provider.StringSerializer = new JsonStringSerializer();
//.NET's XML and JSON DataContract serializers
SqlServerDialect.Provider.StringSerializer = new DataContractSerializer();
MySqlDialect.Provider.StringSerializer = new JsonDataContractSerializer();
//.NET XmlSerializer
OracleDialect.Provider.StringSerializer = new XmlSerializableSerializer();

You can also provide a custom serialization strategy by implementing IStringSerializer:

public interface IStringSerializer
{
    To DeserializeFromString<To>(string serializedText);
    object DeserializeFromString(string serializedText, Type type);
    string SerializeToString<TFrom>(TFrom from);
}
like image 44
mythz Avatar answered Sep 30 '22 01:09

mythz