views:

125

answers:

4

I've got an object that uses System.Version as a property. I want this object to be mapped into my table, storing the version as a string. what's the best way to go about doing this with NHibernate v1.2?

public class MyClass
{
  public Version MyVersion {get; set;}
}

not sure what to do with the propery mapping

<property name="MyVersion" column="MyVersion" not-null="true" />

this gives me errors saying "Invalid attempt to GetBytes on column 'MyVersion0_0_'. The GetBytes function can only be used on columns of type Text, NText, or Image." If I use type="string" in the map, i get casting errors.

suggestions?

+4  A: 

You would need to write an NHibernate user type, that returns a property value of type Version, but persists as a string. There is a skeleton user type implementation here that takes care of some of the work for you.

David M
This is exactly what I've done in my code previously, works well.
Michael Greene
I've done it in many other cases, but not Version. If you have working code, you might like to post an answer with it...
David M
that URL is not responding. anyone have a cached version of it?
Derick Bailey
David M
A: 

David M's answer is probably the most robust way to go about it.

As an alternative, you could convert the property to a string and just use that. I'm not sure how big a change that is in your model though.

David Hogue
+2  A: 

David M's suggestion and article link were great. Just in case anyone else has problems getting to that site, though ( i had to load it up from google cache), here is my solution:


    public abstract class BaseImmutableUserType : IUserType
    {
        public abstract object NullSafeGet(IDataReader rs, string[] names, object owner);
        public abstract void NullSafeSet(IDbCommand cmd, object value, int index);
        public abstract SqlType[] SqlTypes { get; }

        public new bool Equals(object x, object y)
        {
            if (ReferenceEquals(x, y))
            {
                return true;
            }

            if (x == null || y == null)
            {
                return false;
            }

            return x.Equals(y);
        }

        public int GetHashCode(object x)
        {
            return x.GetHashCode();
        }

        public object DeepCopy(object value)
        {
            return value;
        }

        public object Replace(object original, object target, object owner)
        {
            return original;
        }

        public object Assemble(object cached, object owner)
        {
            return DeepCopy(cached);
        }

        public object Disassemble(object value)
        {
            return DeepCopy(value);
        }

        public Type ReturnedType
        {
            get { return typeof(T); }
        }

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

    public class VersionUserType: BaseImmutableUserType
    {

        public override SqlType[] SqlTypes 
        { 
            get
            {
                return new SqlType[]{new StringSqlType()};
            } 
        }

        public override object NullSafeGet(IDataReader rs, string[] names, object owner)
        {
            Version version = null;
            var value = NHibernateUtil.String.NullSafeGet(rs, names) as string;
            if (value != null)
                version = new Version(value);
            return version;
        }

        public override void NullSafeSet(IDbCommand cmd, object value, int index)
        {
            object valueToSet;
            Version version = value as Version;
            if (version != null)
            {
                valueToSet = version.ToString();
            }
            else
            {
                valueToSet = DBNull.Value;
            }

            NHibernateUtil.String.NullSafeSet(cmd, valueToSet, index);
        }
    }

and the mapping file now has this property:

<property name="MyVersion" column="MyVersion" not-null="true" type="My.Namespace.VersionUserType, My.Assembly" />

Derick Bailey
A: 

Another thumbs-up for David M's answer. However, you'll note that System.Version has a constructor that takes a string representation, as well as a ToString() that produces the same format, so you could map the property as a simple string in NHibernate and map it to a private string field directly, then have a facade property typed to System.Version something like this:

public System.Version Version
{
    get { return new System.Version(_versionAsString); }
    set { _versionAsString = value.ToString(); }
}

I don't see it as bad practice particularly, and it's easy enough to do. You might need to use an internal property rather than a field if you're going to proxy the type for lazy-loading, but otherwise it should work.

DotNetGuy