Let me start with this... Suppose you have a class, Customer, and a map for it:
public class CustomerMap : ClassMap<Customer> { public CustomerMap() { Table("tblCustomers"); Id(x => x.Id, "CustomerID") .GeneratedBy.Identity() .CustomType<BaseIdUserType<CustomerId>>() .GeneratedBy.Identity() .UnsavedValue(0); CustomerId just extends BaseId which wraps an int. And BaseIdUserType<TId> is a custom NHibernate UserType for these wrapped int's: internal static class BaseIdUserTypeConstants { internal static readonly Type[] ConstructorTypes = new[] {typeof (int)}; internal static readonly SqlType[] SqlTypes = new[] {NHibernateUtil.Int32.SqlType}; } /// <summary> /// Custom NHibernate user type for subclasses of <see cref="BaseId"/>. /// /// Based on http://darrell.mozingo.net/2009/02/10/generic-nhibernate-user-type-base-class/ /// </summary> /// <typeparam name="TId">The type of the ID class</typeparam> public class BaseIdUserType<TId> : IEnhancedUserType where TId : BaseId { public new bool Equals(object x, object y) { return object.Equals(x, y); } public int GetHashCode(object x) { if(x == null) return 0; return x.GetHashCode(); } public object NullSafeGet(IDataReader rs, string[] names, object owner) { object obj = NHibernateUtil.Int32.NullSafeGet(rs, names[0]); if ( obj==null ) return null; int idValue = (int) obj; TId id = ToId(idValue); return id; } private TId ToId(int idValue) { return (TId)Constructor.Invoke(new object[] {idValue}); } private ConstructorInfo Constructor { get { if (_constructor == null) { _constructor = typeof (TId).GetConstructor(BaseIdUserTypeConstants.ConstructorTypes); if(_constructor == null) throw new SystemException(string.Format("{0} does not have a constructor of the form {0}(int)", typeof(TId).Name)); } return _constructor; } } private ConstructorInfo _constructor; public void NullSafeSet(IDbCommand cmd, object value, int index) { if (value == null) { ((IDataParameter)cmd.Parameters[index]).Value = DBNull.Value; } else { TId id = (TId)value; ((IDataParameter)cmd.Parameters[index]).Value = id.Value; } } public object DeepCopy(object value) { return value; // Because BaseId's are immutable, the same instance can stand in for a "copy" } public object Replace(object original, object target, object owner) { return original; // Becuase BaseId's are immutable, we can return the first value (the original value), as per the IUserType docs } public object Assemble(object cached, object owner) { return DeepCopy(cached); } public object Disassemble(object value) { return DeepCopy(value); } public SqlType[] SqlTypes { get { return BaseIdUserTypeConstants.SqlTypes; } } public Type ReturnedType { get { return typeof (TId); } } public bool IsMutable { get { return false; } } public override string ToString() { return string.Format("BasedIdUserType[{0}]", typeof (TId).Name); } public object FromXMLString(string xml) { return ToId(Convert.ToInt32(xml)); } public string ObjectToSQLString(object value) { return Convert.ToString(((TId)value).Value); } public string ToXMLString(object value) { return Convert.ToString(((TId)value).Value); } } At runtime, this produces an exception: System.InvalidOperationException: Identity type must be integral (int, long, uint, ulong) at FluentNHibernate.Mapping.GeneratorBuilder.EnsureIntegralIdenityType() at FluentNHibernate.Mapping.GeneratorBuilder.Identity() at FluentNHibernate.Mapping.IdentityGenerationStrategyBuilder`1.Identity() at MySys.Customers.CustomerMap..ctor() But this in fact is a false constraint! If I swap the GeneratedBy with this, it works absolutely fine (I have it in production like this): .GeneratedBy.Custom("identity") So I can bypass the fluent methods to explicitly put what the fluent method would have used, were it not for the over-zealous guard in GeneratorBuilder.Identity(). On Wednesday, October 29, 2014 5:58:04 AM UTC-4, Gleb Chermennov wrote: > > Unfortunately, I didn't - got swamped with preparing pre-release and other > things. But that doesn't mean I'm giving up. > Can you provide full code sample that reproduces the problem? > > вторник, 28 октября 2014 г., 21:51:45 UTC+4 пользователь Trinition написал: >> >> Did you ever get a chance to investigate this? >> >> On Saturday, July 12, 2014 4:18:34 PM UTC-4, Gleb Chermennov wrote: >>> >>> Let me investigate this and I'll come back to you. Sorry I haven't >>> looked into that before. >>> >>> суббота, 12 июля 2014 г., 3:38:08 UTC+4 пользователь Trinition написал: >>>> >>>> I opened an issue in GitHub >>>> <https://github.com/jagregory/fluent-nhibernate/issues/230> about >>>> this, but it's been idle. Maybe it's because I'm doing something wrong, >>>> so >>>> I wanted to check here. >>>> >>>> Basically, I'm using a special wrapper class around an int for some of >>>> my entity IDs. The values are still generated by IDENTITY in the >>>> database, >>>> but the properties in the classes aren't just ints. I've base a custom >>>> UserType for it so I could try to fluently map like this: >>>> >>>> Id(x => x.Id) >>>> .GeneratedBy.Identity() >>>> .CustomType<BaseIdUserType<FooId>>() >>>> .UnsavedValue(0); >>>> >>>> Fluent NHibernate throws the exception from >>>> EnsureIntegralIdenityType(). However, if I cheat and work-around Fluent >>>> NHibernate's restriction, everything works just fine: >>>> >>>> Id(x => x.Id) >>>> .GeneratedBy.Custom("identity") >>>> .CustomType<BaseIdUserType<FooId>>() >>>> .UnsavedValue(0); >>>> >>>> Is there some other way to get an Custom UserType to work with the >>>> standard .Identity() generator? >>>> >>> -- You received this message because you are subscribed to the Google Groups "Fluent NHibernate" group. To unsubscribe from this group and stop receiving emails from it, send an email to fluent-nhibernate+unsubscr...@googlegroups.com. To post to this group, send email to fluent-nhibernate@googlegroups.com. Visit this group at http://groups.google.com/group/fluent-nhibernate. For more options, visit https://groups.google.com/d/optout.