Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

nHibernate mapping to custom types

I have a Oracle database and one of the fields is a date range field. It is basically just stored in the database as a VARCHAR(40) in the format YYYY/MM/DD-YYYY/MM/DD. I want to map it in nHibernate to a custom class I have created like this

public class DateTimeRange
{
    public DateTimeRange(DateTime fromTime, DateTime toTime)
    {
        FromTime = fromTime;
        ToTime = toTime;
    }

    public override string ToString()
    {
        return String.Format("{0} to {1}", FromTime.ToString("HH:mm:ss"), ToTime.ToString("HH:mm:ss"));
    }

    public DateTime FromTime { get; set; }

    public DateTime ToTime { get; set; }
}

How can I map to custom classes like this?

like image 522
Craig Avatar asked Oct 28 '08 02:10

Craig


1 Answers

You need to implement your own IUserType.

See this blog post for details. I'll also paste the relevant section below in case the blog disappears.

In NHibernate, a custom mapping type is a class that derives from either the IUserType or ICompositeUserType interfaces. These interfaces contain several methods that must be implemented, but for our purposes here, we’re going to focus on 2 of them. Consider the following.

  public class TypeClassUserType : IUserType
  {


    object IUserType.NullSafeGet(IDataReader rs, 
      string[] names, 
     object owner) {

     string name = NHibernateUtil.String.NullSafeGet(rs, 
     names[0]) as string;

     TypeClassFactory factory = new TypeClassFactory();
     TypeClass typeobj = factory.GetTypeClass(name);
     return typeobj;
   }

    void IUserType.NullSafeSet(IDbCommand cmd, 
    object value, 
     int index) {

      string name = ((TypeClass)value).Name;
     NHibernateUtil.String.NullSafeSet(cmd, name, index);
    }
  }

Having created this class, I can now explicitly map the association between ActualClass and TypeClass as a simple property on the ActualClass mapping.

<property
  name="Type"
  column="TypeName"
  type="Samples.NHibernate.DataAccess.TypeClassUserType, 
        Samples.NHibernate.DataAccess" />

As NHibernate is in the process of saving an instance of ActualType, it will load and create a new instance of TypeClassUserType and call the NullSafeSet method. As you can see from the method body, I am simply extracting the name from the mapped property (passed in as the value parameter) and setting the extracted name as the value of the parameter to be set in the database. The net result is that although the Type property of ActualClass is TypeClass in the domain model, only the Name property of the TypeClass object gets stored in the database. The converse is also true. When NHibernate is loading an instance of ActualType from the database and the finds a property of my custom mapping type, it loads my custom type and calls the NullSafeGet method. As you can see, my method gets the name from the returned data, calls my flyweight factory to get the correct instance of TypeClass, and then actually returns that instance. The type resolution process happens transparently to my data access classes (and even to NHibernate itself for that matter).

like image 182
TheSoftwareJedi Avatar answered Oct 16 '22 14:10

TheSoftwareJedi