Description
Rob Stacey created an issue — 3rd September 2015, 7:31:34:
Previously I had hbm mapping with:
<id name="Id" column="ColName" type="Name.Space.OraChar, MyAssm.Name" length="10" generator="assigned" />which worked just fine.
The closest I could get with mapping-by-code is:
Id(x => x.Id, m => { m.Length(10); m.Column("ColName"); m.Generator(Generators.Assigned); m.Type(new CustomType(typeof(Name.Space.OraChar), null)); });This throws:
NHibernate.MappingException : Could not determine type for: Name.Space.OraChar, MyAssm.Name, Version=2.0.0.0, Culture=neutral, PublicKeyToken=wHatEver, for columns: NHibernate.Mapping.Column(ColName)Basically I think the Type never gets set because NH can't find it from it's simple name.
However... If I inherit from CustomType overriding the Name property and return the Assembly Qualified Name hey presto, all is well with the world again.
Ricardo Peres added a comment — 12th September 2015, 9:05:06:
Can you submit a failing unit test, with just the bare minimum to be able to reproduce the problem?
Rob Stacey added a comment — 13th September 2015, 6:13:07:
Hi Ricardo,
Unfortunately the jira system keeps failing to attach the test case so...
using System.Collections.Generic; using System.Data; using NHibernate.DomainModel.NHSpecific; using NHibernate.Mapping.ByCode; using NHibernate.SqlTypes; using NHibernate.UserTypes; using NUnit.Framework; namespace NHibernate.Test.NHSpecificTest.NH3824 { public class OraChar : IUserType { public object NullSafeGet(IDataReader rs, string[] names, object owner) { var resultString = NHibernateUtil.String.NullSafeGet(rs, names<0>) as string; return resultString != null ? resultString.TrimEnd() : null; } public void NullSafeSet(IDbCommand cmd, object value, int index) { if (value == null) { NHibernateUtil.AnsiString.NullSafeSet(cmd, null, index); return; } value = ((string)value).TrimEnd(); NHibernateUtil.AnsiString.NullSafeSet(cmd, value, index); } public object DeepCopy(object value) { return value == null ? null : string.Copy((string)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 SqlType[] SqlTypes { get { return new[] { new SqlType(DbType.AnsiStringFixedLength) }; } } public System.Type ReturnedType { get { return typeof(string); } } public bool IsMutable { get { return false; } } bool IUserType.Equals(object x, object y) { if (x == null && y == null) return true; if (x == null | y == null) return false; | return x.Equals(y); } public int GetHashCode(object x) { return x.GetHashCode(); } } public class SubClassedCustomType : Type.CustomType { private readonly string _fqName; public SubClassedCustomType(System.Type userTypeClass, IDictionary<string, string> parameters) : base(userTypeClass, parameters) { _fqName = userTypeClass.AssemblyQualifiedName; } public override string Name { get { return _fqName; } } } public class TestClass { public virtual string StringProperty { get; set; } } public class TestCase { <Test> public void NHibernate*CustomType*SameAssemblyAsMappedClass() { var cfg = TestConfigurationHelper.GetDefaultConfiguration(); var mapper = new ModelMapper(); mapper.Class<TestClass>( m => { m.Id( x => x.StringProperty, mp => mp.Type(new Type.CustomType(typeof(OraChar), null))); }); var hbm = mapper.CompileMappingForAllExplicitlyAddedEntities(); Assert.DoesNotThrow(() => cfg.AddDeserializedMapping(hbm, "TestDomain")); } <Test> public void NHibernate*CustomType*DifferentAssemblyToMappedClass() { var cfg = TestConfigurationHelper.GetDefaultConfiguration(); var mapper = new ModelMapper(); mapper.Class<BasicClass>( m => { m.Id( x => x.StringProperty, mp => mp.Type(new Type.CustomType(typeof(OraChar), null))); }); var hbm = mapper.CompileMappingForAllExplicitlyAddedEntities(); Assert.DoesNotThrow(() => cfg.AddDeserializedMapping(hbm, "TestDomain")); } <Test> public void SubClassed*CustomType*SameAssemblyAsMappedClass() { var cfg = TestConfigurationHelper.GetDefaultConfiguration(); var mapper = new ModelMapper(); mapper.Class<TestClass>( m => { m.Id( x => x.StringProperty, mp => mp.Type(new SubClassedCustomType(typeof(OraChar), null))); }); var hbm = mapper.CompileMappingForAllExplicitlyAddedEntities(); Assert.DoesNotThrow(() => cfg.AddDeserializedMapping(hbm, "TestDomain")); } <Test> public void SubClassed*CustomType*DifferentAssemblyToMappedClass() { var cfg = TestConfigurationHelper.GetDefaultConfiguration(); var mapper = new ModelMapper(); mapper.Class<BasicClass>( m => { m.Id( x => x.StringProperty, mp => mp.Type(new SubClassedCustomType(typeof(OraChar), null))); }); var hbm = mapper.CompileMappingForAllExplicitlyAddedEntities(); Assert.DoesNotThrow(() => cfg.AddDeserializedMapping(hbm, "TestDomain")); } } }
Rob Stacey added a comment — 13th September 2015, 6:20:34:
It would appear that NH is looking in the same assembly as the mapped class for the UserType, this is probably why it surfaced in my particular scenario as my user type was in a different (common) library:
{panel}
09:02:10,608 INFO Environment:426 - NHibernate 4.0.4.GA (assembly 4.0.0.4000)
09:02:11,025 INFO Environment:426 - Bytecode provider name : lcg
09:02:11,027 INFO Environment:426 - Using reflection optimizer
09:02:11,238 INFO Dialect:426 - Using dialect: NHibernate.Dialect.MsSql2008Dialect
09:02:11,314 INFO Binder:438 - Mapping class: NHibernate.DomainModel.NHSpecific.BasicClass -> BasicClass
09:02:11,330 ERROR ReflectHelper:384 - Could not load type NHibernate.DomainModel.NHSpecific.OraChar, NHibernate.DomainModel, Version=4.0.0.4000, Culture=neutral, PublicKeyToken=null.
System.TypeLoadException: Could not load type 'NHibernate.DomainModel.NHSpecific.OraChar' from assembly 'NHibernate.DomainModel, Version=4.0.0.4000, Culture=neutral, PublicKeyToken=null'.
at System.Reflection.RuntimeAssembly.GetType(RuntimeAssembly assembly, String name, Boolean throwOnError, Boolean ignoreCase, ObjectHandleOnStack type)
at System.Reflection.RuntimeAssembly.GetType(String name, Boolean throwOnError, Boolean ignoreCase)
at NHibernate.Util.ReflectHelper.TypeFromAssembly(AssemblyQualifiedTypeName name, Boolean throwOnError) in c:\Dev\Externals\nhibernate\nhibernate-core-4.0.4.GA\src\NHibernate\Util\ReflectHelper.cs:line 285
09:02:11,333 ERROR Configuration:384 - Could not compile the mapping document: TestDomain
NHibernate.MappingException: Could not compile the mapping document: TestDomain ---> NHibernate.MappingException: Could not determine type for: NHibernate.DomainModel.NHSpecific.OraChar, NHibernate.DomainModel, Version=4.0.0.4000, Culture=neutral, PublicKeyToken=null, for columns: NHibernate.Mapping.Column(StringProperty)
{panel}