NHibernate Image User Type

Supose you want to have in your domain model a property which is of type System.Drawing.Image. On SQL Server, you would map this as a column of type IMAGE, and on your domain model you would define it like this:

public virtual System.Drawing.Image Image

{

    get;

    set;

}

In order to use it with NHibernate, you must define a custom user type, by implementing the NHibernate.UserTypes.IUserType interface. We write a ImageUserType class and register it at the property definition in the .hbm.xml file:

<property name="Image" column="`Image`" type="ImageUserType, MyAssembly"/>

And here is the code;

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using NHibernate.UserTypes;

using System.Data;

using NHibernate.SqlTypes;

using System.Drawing;

using NHibernate;

using System.IO;

using System.Drawing.Imaging;

public class ImageUserType: IUserType

{

    public Object Assemble(Object cached, Object owner)

    {

        return (cached);

    }

    public Object DeepCopy(Object value)

    {

        if (value == null)

        {

            return (null);

        }

        else

        {

            return ((value as ICloneable).Clone());

        }

    }

    public Object Disassemble(Object value)

    {

        return (value);

    }

    public Int32 GetHashCode(Object x)

    {

        return (x != null ? x.GetHashCode() : 0);

    }

    public Boolean IsMutable

    {

        get

        {

            return (false);

        }

    }

    public Object NullSafeGet(IDataReader rs, String [] names, Object owner)

    {

        Byte [] data = NHibernateUtil.Binary.NullSafeGet(rs, names [ 0 ]) as Byte [];

        if (data != null)

        {

            using (Stream stream = new MemoryStream(data))

            {

                Image image = Image.FromStream(stream);

                return (image);

            }

        }

        else

        {

            return (null);

        }

    }

    public void NullSafeSet(IDbCommand cmd, Object value, Int32 index)

    {

        if (value == null)

        {

            NHibernateUtil.Binary.NullSafeSet(cmd, null, index);

        }

        else

        {

            using (MemoryStream stream = new MemoryStream())

            {

                Image image = value as Image;

                image.Save(stream, ImageFormat.Png);

                NHibernateUtil.String.NullSafeSet(cmd, stream.GetBuffer(), index);

            }

        }

    }

    public Object Replace(Object original, Object target, Object owner)

    {

        return (original);

    }

    public Type ReturnedType

    {

        get

        {

            return (typeof(Image));

        }

    }

    public SqlType [] SqlTypes

    {

        get

        {

            return (new SqlType [] { new SqlType(DbType.Binary) });

        }

    }

    Boolean IUserType.Equals(Object o1, Object o2)

    {

        return (Object.Equals(o1, o2));

    }

}

This saves the image object as an array of bytes (in PNG format, to use compression) and loads it into an System.Drawing.Image. The image is immutable, so a lot of methods are quite simple.

I think the code is easily understandable, but if you have problems, let me know!

Bookmark and Share

                             

6 Comments

  • Nice code, thanks a lot. I have basically converted the code into VB.NET, and have only encountered 1 problem... basically, when I bind a windows form picturebox to an SQL image via NHibernate, the session.IsDirty property is set to true IMMEDIATELY, without any actual changes occuring. If the image in the DB is null then it is OK and the IsDirty property works as expected. Any ideas?

  • Hello, Dominik!
    Thanks for your comment. I will look into it and give you feedback. You know, I'm not a Windows Forms guy, I'm more into ASP.NET... :-)
    RP

  • Thanks for your quick response. I assume since the issue with "isDirty" lies more on the NHibernate side of things that it would not matter if it's an ASP.NET app or a Windows Forms app. But, I'll run up a quick ASP.NET page to see what happens. Thanks again for your response!

  • Just a question, this code should work for a SQL Type such as varbinary(MAX) too? If the image is stored in that column?

  • Javier,
    That's exactly what it's for! :-)

  • Javier and Dominik:
    You can find a working (fixed) example on my SkyDrive: http://cid-0450c015fc418de2.skydrive.live.com/browse.aspx/.Public/TechDays%202010

Comments have been disabled for this content.