Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Persisting the state pattern using Entity Framework

I am currently developing a project in MVC 3. I've separated my concerns so there are projects such as Core, Repository, UI, Services etc. I have implement the Repository, UnitOfWork and most importantly the State pattern.

I am using Entity Framework 4.3 to persist my data and I have come across a rather annoying situation involving the persistence of the current state. Below are some class examples:

public class Request
{
    public int RequestId { get; set; }

    public State CurrentState { get; set; }
}

public abstract class State
{
    [Key]
    public string Name {get; set;}

    public virtual void OpenRequest(Request request)
    {}

    public virtual void CloseRequest(Request request)
    {}
}

public class RequestIsOpenState : State
{
    public RequestIsOpenState()
    {
        this.Name = "Open";
    }

    public override void CloseRequest(Request request)
    {
        request.CurrentState = new RequstIsClosedState();
    }
}

public class RequestIsClosedState : State
{
    public RequestIsClosedState()
    {
        this.Name = "Closed";
    }

    public override void OpenRequest(Request request)
    {
        request.CurrentState = new RequstIsOpenState();
    }
}

Using the above example I will get a primary key violation exception because it tries to create a NEW state in the States table.

Because the state change is done within the domain layer, I can't just 'get' the state from the repository and set it using the foreign key by doing something like this:

Request request = unitOfWork.RequestRepository.Find(1);
request.CurrentState = unitOfWork.StateRepository.Find("Closed");

I'm aware I have the option of not mapping the state property, and persist a string property in the request class and then convert them back and forth through a factory on a get and set when the entity is hydrated (see this answer).

All I want to do is persist the state class, so when the request is returned I can access the state methods immediately without having loads of EF stuff polluting my domain layer just to handle one persistence issue. Another benefit of which would be it gives me the added bonus of having a table in SQL to query against known states.

like image 504
Heberda Avatar asked Feb 14 '14 16:02

Heberda


1 Answers

I think you can improve it by caching the State instances creating it only once, to avoid making the list each time and avoid the foreach:

public static class StateFactory
{
    private static Dictionary<string, State> statesCache = FindAllDerivedStates();

    public static State GetState(string stateTypeName)
    {
        return statesCache[stateTypeName];
    }

    private static Dictionary<string, State> FindAllDerivedStates()
    {
        var derivedType = typeof(State);
        var assembly = Assembly.GetAssembly(typeof(State));
        return assembly.GetTypes().Where(t => t != derivedType && derivedType.IsAssignableFrom(t))
                    .Select(t => (State)Activator.CreateInstance(t))
                    .ToDictionary(k => k.Name);
    }
}
like image 184
thepirat000 Avatar answered Oct 23 '22 01:10

thepirat000