Persisting of unknown (or new) types with XPO

In XPO, an ORM product by Developer Express, it’s possible to use a custom “value converter” to persist information when the standard mapping techniques are not sufficient. This provides a flexible approach that can be used in many different scenarios.

Nullable types

Although the Developer Express knowledge base provides an article that shows how to persist a bitmap, I had never actually used that approach. With .NET 2.0, I was thinking about persisting nullable types and I found that XPO 1 doesn’t have support for that out of the box. The support guys sent me a sample showing how a value converter can be used to extend the mapping to include nullable types. I extended that code to create a generic value converter that can be used for any nullable type. Here’s the code for that:

  public class NullableValueConverter<T> : ValueConverter where T: struct {
    public NullableValueConverter( ) {
      storageType = typeof(T);
    }

    private Type storageType;
    public override Type StorageType {
      get { return storageType; }
    }

    public override object ConvertToStorageType(object value) {
      Nullable<T> nullableValue = (Nullable<T>) value;
      return nullableValue.HasValue ? (object) nullableValue.Value : null;
    }

    public override object ConvertFromStorageType(object value) {
      return (Nullable<T>) (value == null ? null : value);
    }
  }

Now how do you use that thing? It’s simple: just decorate a property that has a nullable type with the ValueConverterAttribute:

  private int? intVal;
  [ValueConverter(typeof(NullableValueConverter<int>))]
  public int? IntVal {
    get { return intVal; }
    set { intVal = value; }
  }

With newer versions of XPO (I’m not sure if that feature is in any released version yet, if it isn’t and you want it (and you are a customer), feel free to send mail to support@devexpress.com) you can also register the value converter for a type globally, so all properties of that type will be converted automatically. Here’s how:

  Session.DefaultSession.Dictionary.RegisterValueConverter(
    new NullableValueConverter<int>(), typeof(int?));

Unknown types

The second interesting use of the value converter was something I stumbled upon a few days later. I had a field in a class that should have been persisted, but I really didn’t know what that field might contain later on. The information would be sent to a server via Remoting and the type depended on the client implementation, so I could only use “object” as the type for the field. Now, how would I go about persisting this information?

The solution I found was to create a value converter that uses serialization to persist the object into a string field. Of course, the object has to be Serializable for this to work, but that’s a requirement for the Remoting part anyway, so I didn’t care. With my SerializableObjectConverter it’s possible to decorate a property like this:

  private object data;
  [ValueConverter(typeof(SerializableObjectConverter)), Size(SizeAttribute.Unlimited)]
  public object Data {
    get { return data; }
    set { data = value; }
  }

And here’s the code for the SerializableObjectConverter:

public class SerializableObjectConverter : ValueConverter {
  public override Type StorageType { get { return typeof(string); } }

  public override object ConvertToStorageType(object value) {
    Assert.Check(value.GetType().IsSerializable, 
      String.Format("The given object ({0}) is not serializable.", value));

    string result = null;

    MemoryStream stream = new MemoryStream();
    try {
      SoapFormatter formatter = new SoapFormatter( );
      formatter.AssemblyFormat = FormatterAssemblyStyle.Simple;
      formatter.Serialize(stream, value);
      result = Encoding.Default.GetString(stream.GetBuffer( ));
    }
    finally {
      stream.Close();
    }

    return result;
  }

  public override object ConvertFromStorageType(object value) {
    object result = null;
            
    MemoryStream stream = new MemoryStream(
      Encoding.Default.GetBytes((string) value));
    try {
      stream.Position = 0;
      SoapFormatter formatter = new SoapFormatter();
      formatter.AssemblyFormat = FormatterAssemblyStyle.Simple;
      result = formatter.Deserialize(stream);
    }
    finally {
      stream.Close();
    }

    return result;
  }
}

3 Comments on Persisting of unknown (or new) types with XPO

  1. Kenneth Ellested // February 10, 2005 at 1:23 pm // Reply

    Very nice – how about trying this with the BinaryFormatter. AFAIK it should take any object, serializeable or not.

    Like

  2. I haven’t tried this right now, but this page in MSDN certainly suggests differently. Where have you heard or seen that the BinaryFormatter can serialize objects without the SerializableAttribute?Of course, using the binary format has its advantages because the stored data will be more compact and I guess the serialization process will probably be faster, too. But I usually prefer to use text (xml) based formats these days because memory and processing power aren’t the scarce resources they used to be. Plus, I can always look into the database with any tool and – more or less – read what’s in the field if it’s in SOAP format.

    Like

  3. Kenneth Ellested // February 15, 2005 at 12:26 pm // Reply

    I guess I have confused something then. I just remember an issue, trying to serialize some objects back in time when .net was initially released. It wasn’t possible without using the binary formatter. Maybe it had something to do with the object graph. Anyway, I haven’t had anyuse for it since, so until now I just believed that the binary formatter was capable ofserializing any objects. Maybe I also confused it with the ISerializable interface.

    Like

Leave a Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s