C# 无法在具有CustomType的查询中强制转换为IConvertible

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

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

_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>();
    }
}