无法在使用 CustomType 的查询中转换为 IConvertible
Cannot cast to IConvertible in Query with CustomType
当运行使用 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();
}
}
我有点 "understand" 为什么会发生此异常,我可以通过实现 IConvertible
(我不希望在我的值对象中使用)或明确地将 employeeNumber
强制转换为int
.
但是我希望这段代码 运行 开箱即用,特别是因为我已经在 EmployeeNumber
中定义了一个隐式转换为 int operator
,然而这似乎不是由 NHibernate 使用。
在这种情况下是否可以通知 NHibernate 使用此 operator
?
还有其他解决方案吗? (理想情况下,如果它编译,它 运行s)
我注定要使用前两个解决方案中的一个(IConvertible/explicit cast)吗?
解决方案是为不同的值对象创建我自己的自定义类型:
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>();
}
}
当运行使用 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();
}
}
我有点 "understand" 为什么会发生此异常,我可以通过实现 IConvertible
(我不希望在我的值对象中使用)或明确地将 employeeNumber
强制转换为int
.
但是我希望这段代码 运行 开箱即用,特别是因为我已经在 EmployeeNumber
中定义了一个隐式转换为 int operator
,然而这似乎不是由 NHibernate 使用。
在这种情况下是否可以通知 NHibernate 使用此 operator
?
还有其他解决方案吗? (理想情况下,如果它编译,它 运行s)
我注定要使用前两个解决方案中的一个(IConvertible/explicit cast)吗?
解决方案是为不同的值对象创建我自己的自定义类型:
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>();
}
}