Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement typesafe enum pattern in entity framework core rc2

How can I implement the typesafe enum pattern in entity framework core rc2?

public class TestStatus
{
    [Column("Id")]
    public int Id { get; private set; }

    [Column("Description")]
    public string Description { get; private set; }

    [Column("LongDescription")]
    public string LongDescription { get; private set; }

    private TestStatus(int id
        , string description
        , string longDescription)
    {
        Id = id;
        Description = description;
        LongDescription = longDescription;
    }

    public TestStatus() { }

    public static readonly TestStatus Active = new TestStatus(1, "Active", "Active Long Description");
    public static readonly TestStatus Pending = new TestStatus(2, "Pending", "Pending Long Description");
    public static readonly TestStatus Cancelled = new TestStatus(3, "Cancelled", "Cancelled Long Description");
}

The id generation strategy is set in OnModelCreating:

builder.Entity<TestStatus>()
    .Property(s => s.Id)
    .ValueGeneratedNever();

This is a simplified example, but the real code was working in rc1. When upgrading to rc2, I had to add the Column attributes so that the properties would be mapped (I assume this is because of the private setter). When attempting to assign the typesafe enum value:

var i = new TestItem
{
    Name = "Test Item 2",
    Status = TestStatus.Active
};
_context.Items.Add(i);
_context.SaveChanges();

I get one of the following errors depending on the use case:

InvalidOperationException: The instance of entity type 'TestStatus' cannot be tracked because another instance of this type with the same key is already being tracked. For new entities consider using an IIdentityGenerator to generate unique key values.

Or

SqlException: Violation of PRIMARY KEY constraint 'PK_Statuses'. Cannot insert duplicate key in object 'dbo.Statuses'. The duplicate key value is (1). The statement has been terminated.

I understand the error. EF thinks that I am trying to create a new instance with the same Id. How can I tell EF that these instances should be considered the same? I can workaround this by moving away from the typesafe enum pattern. I would just like to make it work with the pattern if possible. It was working in rc1.

like image 440
Eric Scott Avatar asked May 25 '16 13:05

Eric Scott


1 Answers

Since you are using the Type-Safe Pattern there is no need to persist the whole object. Simply store the id and create a wrapper like so:

    [Required]
    protected string ObjectTypeValue { get; set; }

    [NotMapped]
    public ObjectType Type
    {
        get { return ObjectType.Parse(ObjectTypeValue); }
        set { ObjectTypeValue = value.Print(); }
    }

For some reasons I use a string as an Id, but you can use any type you like.

like image 148
Sam Avatar answered Oct 23 '22 04:10

Sam