views:

52

answers:

1

I am creating a message queue in a database. Each queued item stores a ID and a couple of other things. But the key field is IncomingMessage. In the database I am storing a serialized version of the IncomingMessage because it can be one of a number of types (like NewWorkorderMessage or EmployeeStatusChangeMessage). So the field in my QueuedMessage class _incomingMessage is a string.

However, I would like to avoid the usual required public virtual string QueuedMessage{get;set;} business and simply have a public object GetMessage() and public SetMessage(object message) method to deal with automatically serialized the .NET class in to the XML. Naturally the calling application wants to deal with instances of Message classes, not XML that it has to serialize/deserialize.

Using FluentNHibernate I'm not sure how to do this. I've tried a couple of different approaches such as the following, but this still requires me to have the property.

Any ideas? Thanks.

            Map(x => x.IncomingMessage)
            .Not.Nullable()
            .WithLengthOf(3000)
            .Access.AsReadOnlyPropertyThroughCamelCaseField(Prefix.Underscore);
A: 

Well, I've done something similar with Images. I store images as blobs in the DB, but want to access them as Image classes on my POCO classes. I did this by using the IPropertyAccessor interface.

My Fluent NHibernate looks like this

        Map(entity => entity.Image)
            .Access.Using<ImagePropertyAccessor>()
            .Nullable();

and my IPropertyAccessor looks like this:

public class ImagePropertyAccessor : IPropertyAccessor
{
    #region Setter

    private class ImageGetterSetter : IGetter, ISetter {
        PropertyInfo _property;
        ImageFormat _imageFormat;
        public ImageGetterSetter(PropertyInfo property, ImageFormat imageFormat)
        {
            if (property == null) throw new ArgumentNullException("property");
            if (property.PropertyType != typeof(Image)) throw new ArgumentException("property");
            _property = property;
            _imageFormat = imageFormat;
        }

        public void Set(object target, object value) {
            var image = Deserialise((byte[]) value);
            _property.SetValue(target, image, null);
        }

        public object Get(object target)
        {
            var image = (Image)_property.GetValue(target, null);
            var data = Serialise(image);
            return data;
        }

        private byte[] Serialise(Image image)
        {
            if (image == null)
                return null;
            var ms = new MemoryStream();
            image.Save(ms, _imageFormat);
            return ms.ToArray();
        }

        private Image Deserialise(byte[] data)
        {
            if (data == null || data.Length == 0)
                return null;
            var ms = new MemoryStream(data);
            return Image.FromStream(ms);
        }

        public object GetForInsert(object owner, IDictionary mergeMap, ISessionImplementor session)
        {
            return Get(owner);
        }

        public Type ReturnType
        {
            get { return typeof (byte[]); }
        }

        public string PropertyName {
            get { return _property.Name; }
        }

        public MethodInfo Method {
            get { return null; }
        }
    }

    #endregion

    public IGetter GetGetter(Type theClass, string propertyName) {
        return new ImageGetterSetter(theClass.GetProperty(propertyName), ImageFormat.Bmp);
    }

    public ISetter GetSetter(Type theClass, string propertyName) {
        return new ImageGetterSetter(theClass.GetProperty(propertyName), ImageFormat.Bmp);
    }

    public bool CanAccessThroughReflectionOptimizer {
        get { return false; }
    }
}

What I do not know, or rather have not investigated, is the effect of pushing the serialisation/deserialisation into NHibernate. Obviously there is an extra overhead associated with this. In my example it's not too bad, as I'm not dealing with masses of entities and data. For performance reasons you may be better having a deserialised string and exposing your own methods to convert this. But the IPropertyAccessor is good for preserving the design of your POCO classes.

Chris Kemp