代码之家  ›  专栏  ›  技术社区  ›  Spotted

无法在customtype为的查询中强制转换为iconvertible

  •  0
  • Spotted  · 技术社区  · 6 年前

    使用nhibernate会话运行此代码时:

    _session.Query<Order>().SingleOrDefault(o => o.EmployeeNumber == employeeNumber);
    

    我得到以下异常:

    Unable to cast object of type 'EmployeeNumber' to type 'System.IConvertible'.
    

    相关代码:

    public class Order : FOAggregateRoot
    {
        private readonly int _employeeNumber;
        public virtual EmployeeNumber EmployeeNumber => (EmployeeNumber)_employeeNumber;
        private readonly IList<OrderLine> _products;
        public virtual IReadOnlyList<OrderLine> Products => _products.ToList();
        public virtual Price Total => (Price)_products.Sum(line => line.Total);
    
        public Order(EmployeeNumber employeeNumber) : base(Guid.NewGuid())
        {
            _products = new List<OrderLine>();
            _employeeNumber = employeeNumber;
        }
    
        protected Order() { }
    }
    
    public sealed class EmployeeNumber : SingleValueObject<int>
    {
        public EmployeeNumber(int value)
        {
            Value = value;
        }
    
        public static implicit operator int(EmployeeNumber number)
        {
            return number.Value;
        }
    
        public static explicit operator EmployeeNumber(int number)
        {
            return new EmployeeNumber(number);
        }
    }
    
    public class OrderMap : ClassMap<Order>
    {
        public OrderMap()
        {
            Id(Entity.Expressions<Order>.Id);
            Map(x => x.Uid);
            Map(x => x.EmployeeNumber)
                .Unique()
                .CustomType<int>().Access.CamelCaseField(Prefix.Underscore);
            HasMany(x => x.Products)
                .Inverse()
                .Cascade.All()
                .Not.LazyLoad();
        }
    }
    

    我有点“理解”为什么会发生这种异常,我可以通过实现 IConvertible (我不想在我的值对象中)或明确地 employeeNumber int .

    不过,我本希望这段代码能够开箱即用,特别是因为我定义了一个隐式强制转换 int operator 在里面 EmployeeNumber ,但NHibernate似乎并不使用它。

    可以通知NHibernate使用这个吗 operator 在这种情况下?

    还有其他解决方案吗?(理想情况下,如果编译,则运行)

    我注定要使用两个第一解决方案之一(iconvertible/explicit cast)吗?

    0 回复  |  直到 6 年前
        1
  •  1
  •   Spotted    6 年前

    解决方案是为不同的值对象创建自己的自定义类型:

    public sealed class EmployeeNumberUserType : SingleValueObjectType<EmployeeNumber>
    {
        protected override NullableType PrimitiveType => NHibernateUtil.Int32;
    }
    
    public abstract class SingleValueObjectType<TValueObject> : IUserType where TValueObject : class
    {
        public SqlType[] SqlTypes => new[] { PrimitiveType.SqlType };
    
        public Type ReturnedType => typeof(TValueObject);
    
        public bool IsMutable => false;
    
        public object Assemble(object cached, object owner) => cached;
    
        public object DeepCopy(object value) => value;
    
        public object Disassemble(object value) => value;
    
        public new bool Equals(object x, object y) => x?.Equals(y) ?? y?.Equals(x) ?? true;
    
        public int GetHashCode(object x) => x?.GetHashCode() ?? 0;
    
        public object NullSafeGet(DbDataReader rs, string[] names, ISessionImplementor session, object owner)
        {
            var obj = PrimitiveType.NullSafeGet(rs, names[0], session, owner);
            if (obj == null) return null;
            else return Activator.CreateInstance(typeof(TValueObject), obj);
        }
    
        public void NullSafeSet(DbCommand cmd, object value, int index, ISessionImplementor session)
        {
            if (value == null) cmd.Parameters[index].Value = DBNull.Value;
            else cmd.Parameters[index].Value = value.GetType()
                                                    .GetProperty("Value", BindingFlags.Instance | BindingFlags.NonPublic)
                                                    .GetValue(value);
        }
    
        public object Replace(object original, object target, object owner) => original;
    
        protected abstract NullableType PrimitiveType { get; }
    }
    

    并在映射中明确使用此自定义类型:

    public class OrderMap : ClassMap<Order>
    {
        public OrderMap()
        {
            Id(Entity.Expressions<Order>.Id);
            Map(x => x.EmployeeNumber)
                .Unique()
                .CustomType<EmployeeNumberUserType>();
        }
    }