C# 无法在具有CustomType的查询中强制转换为IConvertible
使用NHibernate会话运行此代码时:C# 无法在具有CustomType的查询中强制转换为IConvertible,c#,nhibernate,C#,Nhibernate,使用NHibernate会话运行此代码时: _session.Query<Order>().SingleOrDefault(o => o.EmployeeNumber == employeeNumber); 相关代码: public class Order : FOAggregateRoot { private readonly int _employeeNumber; public virtual EmployeeNumber EmployeeNumber
_session.Query<Order>().SingleOrDefault(o => o.EmployeeNumber == employeeNumber);
相关代码:
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();
}
}
公共类顺序:FOAggregateRoot
{
私人只读int_employeeNumber;
公共虚拟EmployeeNumber EmployeeNumber=>(EmployeeNumber)\u EmployeeNumber;
私有只读IList_产品;
公共虚拟IReadOnlyList产品=>_Products.ToList();
公共虚拟价格总计=>(价格)\产品.Sum(行=>行.Total);
公共秩序(EmployeeNumber EmployeeNumber):基本(Guid.NewGuid())
{
_产品=新列表();
_employeeNumber=雇员编号;
}
受保护顺序(){}
}
公共密封类EmployeeNumber:SingleValueObject
{
公共雇员编号(int值)
{
价值=价值;
}
公共静态隐式运算符int(EmployeeNumber)
{
返回数字。值;
}
公共静态显式运算符EmployeeNumber(整数)
{
返回新员工编号(编号);
}
}
公共类OrderMap:ClassMap
{
公共秩序地图()
{
Id(Entity.Expressions.Id);
Map(x=>x.Uid);
映射(x=>x.EmployeeNumber)
.Unique()
.CustomType().Access.CamelCaseField(前缀为.下划线);
有很多(x=>x.Products)
.Inverse()
.Cascade.All()
.Not.LazyLoad();
}
}
我有点“理解”为什么会发生这种异常,我可以通过实现IConvertible
(我不想在我的值对象中使用它)或将employeeNumber
显式转换为int
来解决它
然而,我本以为这段代码会开箱即用,特别是因为我在EmployeeNumber
中定义了一个隐式转换到int操作符
,但NHibernate似乎没有使用它
在这种情况下,是否可以通知NHibernate使用此操作员
还有其他解决办法吗?(理想情况下,如果它编译,它将运行)
我注定要使用前两种解决方案(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; }
}
公共密封类EmployeeNumber用户类型:SingleValueObjectType
{
受保护的覆盖NullableType PrimitiveType=>NHibernateUtil.Int32;
}
公共抽象类SingleValueObjectType:IUserType,其中TValueObject:class
{
公共SqlType[]SqlTypes=>new[]{PrimitiveType.SqlType};
公共类型ReturnedType=>typeof(TValueObject);
public bool IsMutable=>false;
公共对象组装(对象缓存,对象所有者)=>cached;
公共对象DeepCopy(对象值)=>值;
公共对象分解(对象值)=>值;
公共新布尔等于(对象x,对象y)=>x?.Equals(y)??y?.Equals(x)??真;
public int GetHashCode(对象x)=>x?.GetHashCode()??0;
公共对象NullSafeGet(DbDataReader、字符串[]名称、ISessionImplementor会话、对象所有者)
{
var obj=PrimitiveType.NullSafeGet(rs,名称[0],会话,所有者);
if(obj==null)返回null;
else返回Activator.CreateInstance(typeof(TValueObject),obj);
}
public void NullSafeSet(DbCommand cmd、对象值、int索引、ISessionImplementor会话)
{
如果(value==null)cmd.Parameters[index].value=DBNull.value;
else cmd.Parameters[index].Value=Value.GetType()
.GetProperty(“值”,BindingFlags.Instance | BindingFlags.NonPublic)
.GetValue(value);
}
公共对象替换(对象原始、对象目标、对象所有者)=>原始;
受保护的抽象NullableType原语类型{get;}
}
并在映射中明确使用此自定义类型:
public class OrderMap : ClassMap<Order>
{
public OrderMap()
{
Id(Entity.Expressions<Order>.Id);
Map(x => x.EmployeeNumber)
.Unique()
.CustomType<EmployeeNumberUserType>();
}
}
public类OrderMap:ClassMap
{
公共秩序地图()
{
Id(Entity.Expressions.Id);
映射(x=>x.EmployeeNumber)
.Unique()
.CustomType();
}
}
你给了我们很多员工的代码,但你似乎在查询订单
。我很快就对你的员工进行了测试(使用列表
并去掉用户名和密码),并且能够查询。SingleOrDefault(e=>e.Number==5)
。请分享订单的代码
据我所知,问题不在该代码中。考虑到这一点,我收回了我的声明。使用列表
而不是查询
进行测试并不是真正具有代表性的,很可能是翻译到后台生成的任何查询语言中的内容。虽然您正在查询和订单
,但没有提供相关代码。@Knoop Oops您是对的,我共享了错误的代码。我编辑了我的问题。是的,问题出现在查询
中,其中NHibernate无法自动从员工编号
中提取int
。感谢您添加订单
代码。是的,我的假设是一样的,可悲的是,我不知道那里到底发生了什么,所以我不能帮你。希望你能找到答案!
public class OrderMap : ClassMap<Order>
{
public OrderMap()
{
Id(Entity.Expressions<Order>.Id);
Map(x => x.EmployeeNumber)
.Unique()
.CustomType<EmployeeNumberUserType>();
}
}