使用NHibernate和FluentMapping的状态模式

时间:2017-09-29 14:11:49

标签: c# nhibernate domain-driven-design

在我们的应用中,我们正在为我们的实体使用状态模式。我们遇到了一个问题,即将状态映射到数据库值。我们当前的解决方案有效,但不支持IQueryable(来自hibernate),因此迫使我们在存储库中调用.ToList()。

这是我们的实体:

public class Gap 
{
    [ommited]

    public virtual IGapState State { get; protected set; }
    public virtual IGapState PreviousState { get; protected set; }
}

目前,我们的IGapState映射如下所示:

public class GapMap : ClassMap<Gap> {
    [ommited]

    Map(x => x.State).CustomType<GapStateType>();
    Map(x => x.PreviousState).CustomType<GapPreviousStateType>()
}

我们的自定义类型如下所示:

public class GapStateType : ICompositeUserType
{
    public bool IsMutable => false;
    public virtual string[] PropertyNames => new string[1] { "State" };
    public IType[] PropertyTypes => new IType[1] { NHibernateUtil.Int32 };
    public Type ReturnedClass => typeof(IGapState);
    public object Assemble(object cached, ISessionImplementor session, object owner) => cached;
    public object DeepCopy(object value) => value;
    public object Disassemble(object value, ISessionImplementor session) => value;
    public new bool Equals(object x, object y) => object.Equals(x, y);
    public int GetHashCode(object x) => x.GetHashCode();
    public object GetPropertyValue(object component, int property)
    {
        IGapState state = (IGapState)component;
        return state.Discriminator;
    }

    public object NullSafeGet(IDataReader dr, string[] names, ISessionImplementor session, object owner)
    {
        State state = (State)NHibernateUtil.Int32.NullSafeGet(dr, names[0]);
        switch (state)
        {
            case State.New:
                return new New();
            case State.InProgress:
                return new InProgress();
            case State.TicketClosedWaitingForEvidence:
                return new TicketClosedWaitingForEvidence();
            case State.EvidenceProvidedWaitingForTicketClosure:
                return new EvidenceProvidedWaitingForTicketClosure();
            case State.EvidenceProvidedWaitingForTicketAssigment:
                return new EvidenceProvidedWaitingForTicketAssigment();
            case State.FalsePositiveWaitingForApproval:
                return new FalsePositiveWaitingForApproval();
            case State.FalsePositiveApproved:
                return new FalsePositiveApproved();
            case State.RiskStateWaitingForApproval:
                return new RiskStateWaitingForApproval();
            case State.RiskStateApproved:
                return new RiskStateApproved();
            case State.Closed:
                return new Closed();
            default:
                return new Null();
        }
    }

    public void NullSafeSet(IDbCommand cmd, object value, int index, bool[] settable, ISessionImplementor session)
    {
        //State state = (State)value;
        //NHibernateUtil.Int32.NullSafeSet(cmd, (int)state, index);
        IGapState state = (IGapState)value;
        NHibernateUtil.Int32.NullSafeSet(cmd, (int)state.Discriminator, index);
    }

    public object Replace(object original, object target, ISessionImplementor session, object owner)
    {
        return target;
    }

    public void SetPropertyValue(object component, int property, object value)
    {
        throw new InvalidOperationException("Discriminator is an immutable object. SetPropertyValue isn't supported.");
    }
}

在存储库中我们调用

public IEnumerable<Gap> FindWatingForApprovalRisk()
{
    return FindAll().ToList().Where(x => x.State.Discriminator == State.RiskStateWaitingForApproval);
}

在我们没有大量实体之前,这一切都很好。当我们切出ToList()并将返回类型更改为IQueryable时,我们得到以下异常:

could not resolve property: State.Discriminator of: 
Exprimo.CBA.Model.Entities.GapPortal.Gap 
[.Count[Exprimo.CBA.Model.Entities.GapPortal.Gap]
(.Where[Exprimo.CBA.Model.Entities.GapPortal.Gap]
(NHibernate.Linq.NhQueryable`1[Exprimo.CBA.Model.Entities.GapPortal.Gap], 
Quote((x, ) => (Equal(Convert(x.State.Discriminator), p1))), ), )]

1 个答案:

答案 0 :(得分:0)

NHibernate不知道如何处理x.State.Discriminator,因为你的映射在x.State停止。

尝试:

.Where(x => x.State == new RiskStateWaitingForApproval())