2016-05-25 25 views
3

如何在實體框架核心rc2中實現typesafe enum pattern如何在實體框架核心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"); 
} 

ID生成策略設置在OnModelCreating:

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

這是一個簡單的例子,但真正的代碼RC1是工作。升級到rc2時,我必須添加列屬性,以便映射屬性(我假設這是因爲私有setter)。當試圖指定類型安全枚舉值:

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

我得到取決於使用情況下,下面的錯誤之一:

出現InvalidOperationException:實體類型「TestStatus」的實例不能因爲另一個實例跟蹤這種具有相同鍵的類型已被跟蹤。對於新實體,請考慮使用IIdentityGenerator生成唯一的鍵值。

或者

SQLEXCEPTION:PRIMARY KEY約束 'PK_Statuses' 的相關規定。不能在對象'dbo.Statuses'中插入重複鍵。重複的鍵值是(1)。該語句已終止。

我明白這個錯誤。 EF認爲我正在嘗試使用相同的ID創建新實例。我如何告知EF這些實例應該被視爲相同?我可以通過遠離類型安全枚舉模式來解決此問題。如果可能的話,我只想讓它與模式一起工作。它在rc1中工作。

+0

爲什麼'TestStatus'對象都具有相同的'Id'? – noox

+0

@noox這是一個錯字。我編輯了這個問題來解決它。謝謝! –

回答

2

由於您使用的是類型安全模式,因此不需要保留整個對象。簡單地存儲ID和創建一個包裝,像這樣:

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

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

對於一些原因,我使用一個字符串作爲id,但你可以使用任何你喜歡的類型。

+1

我花了一兩分鐘的時間來圍繞@sam提出的答案。對於任何可能會遇到此問題的人來說,他所說的是在使用類型安全枚舉的類型上創建一個屬性,該類型只存儲該值(或ID或您稱之爲的任何內容)。這讓EF很開心,因爲它只需存儲一個簡單的類型即可。接下來,只需創建一個「包裝器」,通過在枚舉上調用某種'.Parse'方法將類型安全枚舉公開爲對象。噹噹! – Greg