我們正在使用EF 6.1代碼首次安裝中的一個相當大的模型,我們正在使用實體ID的整數。我們可以使用枚舉作爲類型安全實體ID嗎?
不幸的是,這不像我們想要的那樣安全,因爲可以很容易地混淆id,例如比較不同類型實體(myblog.Id == somePost.Id)或類似實體的id。甚至更糟糕的是:myBlog.Id ++。
因此,我想出了使用輸入ID的想法,所以你不能混淆ID。 所以我們需要一個BlogId類型爲我們的博客實體。現在,顯而易見的選擇是使用包裝在結構中的int,但不能將結構用作關鍵字。而且你不能擴展int ... - 等等,你可以!使用枚舉!
於是我想出了這一點:
public enum BlogId : int { }
public class Blog
{
public Blog() { Posts = new List<Post>(); }
public BlogId BlogId { get; set; }
public string Name { get; set; }
public virtual List<Post> Posts { get; set; }
}
internal class BlogConfiguration : EntityTypeConfiguration<Blog>
{
internal BlogConfiguration()
{
HasKey(b => b.BlogId);
Property(b=>b.BlogId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
}
所以現在我們有類型安全的標識 - 一個比較和BlogId一個帖子ID是一個編譯時錯誤。 我們不能將3添加到BlogId中。 空的枚舉可能看起來有點奇怪,但更多的是實現細節。 我們必須在我們的映射中顯式設置DatabaseGeneratedOption.Identity選項,但這是一次性工作。
在我們開始將所有的代碼轉換爲這種模式之前,是否有任何明顯的問題?
編輯: 我可能需要澄清爲什麼我們必須首先使用ID而不是完整的實體。有時我們需要匹配EF Linq查詢中的實體 - 並且比較實體在那裏不起作用。例如(建立在博客示例上並假設一個更豐富的域模型):在當前用戶博客條目中查找評論。請記住,我們希望在數據庫中做到這一點(我們有很多數據),並且我們假設沒有直接的導航屬性。並且當前用戶未被連接。幼稚的做法是
from c in ctx.Comments where c.ParentPost.Blog.Author == currentUser
這不起作用,因爲你不能比較EF Linq中的實體。 所以我們儘量
from c in ctx.Comments where c.ParentPost.Blog.Id == currentUser.Id
這編譯和運行,但錯誤的 - 它應該是
from c in ctx.Comments where c.ParentPost.Blog.Author.Id == currentUser.Id
類型安全的IDS會抓住它。而且我們有比這更復雜的查詢。嘗試「查找由當前用戶以後未自己評論的特定其他用戶創建的當前用戶博客條目的評論」。
問候,尼爾斯
這是一個聰明的想法,但我不完全相信。使用O/R映射器通常應避免直接處理ID,所以我不確定可以獲得多少ID。如果您正在構建低層基礎架構(如緩存或分層實體),則更有可能需要處理ID,這可能有助於避免錯誤。另一方面,如果你不得不在一個地方處理不同的實體類型,並且你有不同的密鑰,它也可能成爲你的方式。 –
挑戰在於我們有時會在不同的上下文中重用主數據對象。例如,假設每篇博文都與全局類別列表中的類別相關聯。現在,在保存博客帖子時,我們只想設置帖子的CategoryId而不將類別實體對象附加到上下文 - 尤其是因爲許多帖子可能同時使用同一個類別項目。 –
+1爲聰明! – Jim