在Entity Framework Core中編寫實體POCO類的正確方法是什麼?

.net asp.net-core c# entity-framework entity-framework-core

EF Core默認具有“代碼優先心態”,即它應該以代碼優先的方式使用,即使支持數據庫優先方法,它也只是對現有數據庫進行逆向工程和創建代碼優先表示。我的意思是,在代碼“手工”(代碼優先)中創建並從數據庫(通過Scaffold-DbContext命令)生成的模型(POCO類)應該是相同的。

令人驚訝的是,官方EF Core文檔顯示出顯著差異。下面是在代碼中創建的模型的例子: https://ef.readthedocs.io/en/latest/platforms/aspnetcore/new-db.html這裡是逆向工程從現有的數據庫它的例子: HTTPS: //ef.readthedocs.io/en/latest/platforms/aspnetcore/existing-db.html

這是第一種情況下的實體類:

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }

    public List<Post> Posts { get; set; }
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public int BlogId { get; set; }
    public Blog Blog { get; set; }
}

這是第二種情況下的實體類:

public partial class Blog
{
    public Blog()
    {
        Post = new HashSet<Post>();
    }

    public int BlogId { get; set; }
    public string Url { get; set; }

    public virtual ICollection<Post> Post { get; set; }
}

第一個例子是一個非常簡單,非常明顯的POCO類。它在文檔中隨處可見(除了從數據庫生成的示例)。第二個例子有一些補充:

  • 類被聲明為部分 (即使沒有任何地方可以看到它的另一個部分定義)。
  • Navigation屬性的類型為ICollection <T> ,而不僅僅是List <T>。
  • Navigation屬性在構造函數中初始化為新的HashSet <T>() 。在代碼優先的例子中沒有這樣的初始化。
  • 導航屬性聲明為虛擬
  • 生成的上下文類中的DbSet成員也是虛擬的

我嘗試過從數據庫中構建模型(截至本文撰寫時的最新工具)並且它完全按照所示生成實體,因此這不是一個過時的文檔問題。因此官方工俱生成不同的代碼,官方文檔建議編寫不同的(普通的)代碼 - 沒有部分類,虛擬成員,構造初始化等。

我的問題是,嘗試在代碼中構建模型,我應該如何編寫代碼?我喜歡使用ICollection而不是List,因為它更通用,但除此之外,我不確定我是否需要遵循docs或MS工具?我需要將它們聲明為虛擬嗎?我需要在構造函數中初始化它們嗎?等等...

我從舊的EF時代就知道虛擬導航屬性允許延遲加載,但在EF Core中甚至不支持它(並且我不知道任何其他用途)。也許它會影響性能?也許工具嘗試生成面向未來的代碼,這樣當實現延遲加載時,POCO類和上下文將能夠支持它嗎?如果是這樣,我可以拋棄它們,因為我不需要延遲加載(所有數據查詢都封裝在一個回購中)?

不久,請幫助我理解為什麼不同,在代碼中構建模型時應該使用哪種樣式?

一般承認的答案

我試著簡單回答你提到的每一點

  • partial類對工俱生成的代碼特別有用。假設您要實現僅模型派生屬性。對於代碼優先,您只需要在任何地方執行此操作。對於數據庫,如果更新模型,將重寫類文件。因此,如果您想保留擴展代碼,則需要將其放在託管模型之外的其他文件中 - 這是partial幫助您擴展類而無需手動調整自動生成的代碼的地方。

  • ICollection絕對是一個合適的選擇,即使是代碼優先。如果沒有排序語句,您的數據庫可能不會支持已定義的順序。

  • 構造函數初始化至少是一種方便...假設您有一個數據庫方式的空集合,或者您根本沒有加載該屬性。如果沒有構造函數,則必須在代碼中的任意點處明確地處理null情況。你是否應該使用ListHashSet是我現在無法回答的問題。

  • virtual支持為數據庫實體創建代理,這可以幫助完成兩件事:如您所述的延遲加載和更改跟踪。代理對象可以使用setter立即跟踪虛擬屬性的更改,而上下文中的普通對象需要在SaveChanges上進行檢查。在某些情況下,這可能更有效(通常不是)。

  • virtual IDbSet上下文條目允許更輕鬆地設計單元測試的測試模型上下文。其他用例也可能存在。



Related

許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因