2

I have a legacy database that uses zero-padded numbers stored as VARCHAR(8) for the primary key values in the tables. (For example, "00032982")

I want to map these to Int32 properties in my entity objects instead of string.

My first attempt was to create a class that implemented IUserType. But I'm mapping an Id, not a Property, and the mapping-by-code wouldn't compile: (Maybe I'm not doing that part right?)

Argument 1: cannot convert from 'TestQWebApi.Infrastructure.StringIntUserType' to 'NHibernate.Type.IIdentifierType'

I looked at IIdentifierType and it has over 40 members. I looked all over the place and it seemed like creating a custom type that subclasses NHibernate.Type.ImmutableType would be the solution. (...maybe this was my first mistake?)

So, I made a new class based on ImmutableType that zero-pads it in the Set() method:

public class LegacyIntKeyType : ImmutableType, ILiteralType, IDiscriminatorType
{
      public LegacyIntKeyType() : base(SqlTypeFactory.GetString(8))
      {
      }

      public override string Name
      {
        get { return "LegacyIntKeyType"; }
      }

      public override object Get(IDataReader rs, int index)
      {
          try
          {
              return Convert.ToInt32(rs[index]);
          }
          catch (Exception ex)
          {
              throw new FormatException(string.Format("Input string '{0}' was not in the correct format.", rs[index]), ex);
          }
      }

      public override object Get(IDataReader rs, string name)
      {
          try
          {
              return Convert.ToInt32(rs[name]);
          }
          catch (Exception ex)
          {
              throw new FormatException(string.Format("Input string '{0}' was not in the correct format.", rs[name]), ex);
          }
      }

      public override System.Type ReturnedClass
      {
          get { return typeof(Int32); }
      }

      public override void Set(IDbCommand rs, object value, int index)
      {
          ((IDataParameter)rs.Parameters[index]).Value = string.Format("{0:d8}", value.ToString());
      }

      public object StringToObject(string xml)
      {
          return FromStringValue(xml);
      }

      public override object FromStringValue(string xml)
      {
          return Int32.Parse(xml);
      }

          public string ObjectToSQLString(object value, Dialect dialect)
      {
          return value.ToString();
      }

      public override string ToString(object value)
      {
          return value.ToString();
      } 

  }

In my base entity class, I have it defined as an Int32:

public abstract class Entity
{
    public virtual Int32 Id { get; protected set; }
}

Then I tried to map it:

public class ProcedureMap : ClassMapping<Procedure>
{
    public ProcedureMap()
    {            
        Table("procfile");
        Id(x => x.Id, m =>
        {
          m.Column("key_proced");
          m.Type(new LegacyIntKeyType());
        });
        Property(x => x.Name, m => m.Column("procname"));
    }
}

Then I get this exception...which I have the feeling is probably indicating something else. Here's the stack trace:

[MappingException: Could not determine type for: TestQWebApi.Models.LegacyIntKeyType, TestQWebApi, for columns: NHibernate.Mapping.Column(key_proced)]
   NHibernate.Mapping.SimpleValue.get_Type() +317
   NHibernate.Cfg.XmlHbmBinding.ClassIdBinder.CreateIdentifierProperty(HbmId idSchema, PersistentClass rootClass, SimpleValue id) +301
   NHibernate.Cfg.XmlHbmBinding.ClassIdBinder.BindId(HbmId idSchema, PersistentClass rootClass, Table table) +396
   NHibernate.Cfg.XmlHbmBinding.RootClassBinder.Bind(HbmClass classSchema, IDictionary`2 inheritedMetas) +987
   NHibernate.Cfg.XmlHbmBinding.MappingRootBinder.AddRootClasses(HbmClass rootClass, IDictionary`2 inheritedMetas) +104
   NHibernate.Cfg.XmlHbmBinding.MappingRootBinder.AddEntitiesMappings(HbmMapping mappingSchema, IDictionary`2 inheritedMetas) +165
   NHibernate.Cfg.XmlHbmBinding.MappingRootBinder.Bind(HbmMapping mappingSchema) +117
   NHibernate.Cfg.Configuration.AddDeserializedMapping(HbmMapping mappingDocument, String documentFileName) +244

Thanks in advance!

Daniel
  • 21
  • 2

1 Answers1

1

you have to implement NHibernates IUserType

class MyIdUserType : IUserType
{
    public object Assemble(object cached, object owner)
    {
        return DeepCopy(cached);
    }

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

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

    bool IUserType.Equals(object x, object y)
    {
        return Object.Equals(x, y);
    }

    public virtual int GetHashCode(object x)
    {
        return (x != null) ? x.GetHashCode() : 0;
    }

    public bool IsMutable { get { return false; } }

    public object NullSafeGet(IDataReader rs, string[] names, object owner)
    {
        return Int32.Parse((string)NHibernateUtil.String.Get(rs, names[0]));
    }

    public void NullSafeSet(IDbCommand cmd, object value, int index)
    {
        NHibernateUtil.String.Set(cmd, string.Format("{0:d8}", value), index);
    }

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

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

    public SqlType[] SqlTypes { get { return new []{ SqlTypeFactory.GetString(8) }; } }
}
Firo
  • 30,626
  • 4
  • 55
  • 94
  • I should have mentioned it in my original post, but I already tried that. The mapping fails to compile saying: Argument 1: cannot convert from 'TestQWebApi.Infrastructure.StringIntUserType' to 'NHibernate.Type.IIdentifierType' I'm doing an Id mapping here, not a Property mapping. Since IIdentifierType has over 40 members, I tried subclassing NHibernate.Type.ImmutableType as a shortcut. I just tried adding IUserType to my existing class (in my original post) and that didn't work. (Same "Could not determine type" error as original post) Do I need to instead implement IIdentifierType? – Daniel Oct 12 '12 at 17:30
  • i already used IUsertype for id mappings. However i mapped it with fluentnhibernate – Firo Oct 12 '12 at 19:26