Шаблон состояния с Entity Framework

У меня есть модель Enquiry, которая может находиться в одном из двух состояний (их больше, но для целей этого я просто сравню два): New и Closed. Состояние запроса зависит от того, что пользователь может сделать с запросом. Например, закрытый запрос нельзя удалить, тогда как новый запрос можно удалить и т. д. (базовый пример).

Я хочу сохранить это с помощью Entity Framework, но не знаю, как это сделать. Ниже мой код.

Расследование:

public class Enquiry
{
    public int Id { get; set; }
    public string CustomerAccountNumber { get; set; }

    public EnquiryState CurrentState { get; set; }
    public bool CanAddLines { get { return CurrentState.CanAddLines; } }
    public bool CanDelete { get { return CurrentState.CanDelete; } }

    public void ChangeState(EnquiryState currentState)
    {
        CurrentState = currentState;
    }

    public void CloseEnquiry()
    {
        CurrentState.CloseEnquiry();
    }

    /* More methods to change state here */

    public Enquiry()
    {
        CurrentState = new NewEnquiryState(this);
    }
}

Состояние запроса:

public abstract class EnquiryState
{
    internal readonly Enquiry CurrentEnquiry;

    protected EnquiryState(Enquiry currentEnquiry)
    {
        CurrentEnquiry = currentEnquiry;
    }

    public virtual bool CanDelete
    {
        get { return false; }
    }

    public virtual bool CanAddLines
    {
        get { return false; }
    }

    /* More properties here */

    public abstract void CloseEnquiry();

    /* More states here */
}

NewEnquiryState:

public class NewEnquiryState : EnquiryState
{
    public NewEnquiryState(Enquiry enquiry) : base(enquiry) { }

    public override bool CanDelete
    {
        get { return true; }
    }

    public override bool CanAddLines
    {
        get { return true; }
    }

    /* ... */

    public override void CloseEnquiry()
    {
        CurrentEnquiry.ChangeState(new CloseEnquiryState(CurrentEnquiry));
    }

    /* ... */
}

CloseEnquiryState:

public class CloseEnquiryState : EnquiryState
{
    public CloseEnquiryState(Enquiry enquiry) : base(enquiry) { }

    public override bool CanAddLines
    {
        get { return false; }
    }
    public override bool CanDelete
    {
        get { return false; }
    }

    /* ... */

    public override void CloseEnquiry()
    {
        throw new Exception("Closed Enquiry can't be closed");
    }
}

Итак, мой вопрос: я не уверен, как хранить эти разные состояния в базе данных, должен ли я использовать какое-то поле int для каждого состояния и сопоставлять их с Enquiry через FK? Кроме того, нужно ли сопоставлять поля CanAddLines и CanDelete с базой данных? Учитывая, что логика содержится в состоянии, совершенно новое для парадигмы шаблона состояния.


person CallumVass    schedule 01.07.2013    source источник


Ответы (1)


В вашем состоянии нет данных для хранения. Итак, на самом деле вам нужно хранить только тип состояния:

[NotMapped]
public EnquiryState CurrentState { get; set; }

public int StateType
{
    get 
    {
       // get value based on CurrentState
       return (CurrentState is NewEnquiryState) ? 0 : 1;
    }
    set
    {
        // create EnquireState based on value
        CurrentState = value == 0 ? 
            (EnquiryState)new NewEnquiryState(this) : 
            (EnquiryState)new CloseEnquiryState(this);
    }
}

Кстати, вам не нужно переопределять виртуальные члены абстрактного класса, если они уже возвращают то, что вам нужно (например, свойства CanAddLines и CanDelete для CloseEnquiryState)

person Sergey Berezovskiy    schedule 01.07.2013
comment
На самом деле у меня больше состояний, как я уже сказал, я использовал только два, чтобы упростить этот пример, так как я могу учесть это, используя свойство StateType? - person CallumVass; 01.07.2013
comment
@BiffBaffBoff вы можете начать с простого блока переключателей, который будет возвращать состояние в соответствии со значением. Или вы можете переместить эту логику в какую-нибудь фабрику состояний. Также вы можете инкапсулировать тип состояния в объекты состояния. Таким образом, получение значения на основе текущего состояния будет выглядеть как return CurrentState.Type - person Sergey Berezovskiy; 01.07.2013