簡體   English   中英

確定模型是否應具有外鍵/導航屬性

[英]Determining if a model should have foreign keys / navigation properties

我正在構建一個相當簡單的MVC項目,並且仍然要先弄清楚在哪里先使用帶有代碼的導航屬性和外鍵。

這是主要的模型類:

public class GroceryItem
{
    public int ID { get; set; }
    public string Name { get; set; }
    public GroceryCategory Category { get; set; }
    public QualityProfile Quality { get; set; }
    public GroceryStore BestStore { get; set; }
    public double BestPrice { get; set; }
    public double LastSeenPrice { get; set; }

    //Navigation Properties
    public virtual ICollection<GroceryItem> SimilarItems { get; set; }
}

這些是相關的類:

public class GroceryStore
{
    public int ID { get; set; }
    public string Name { get; set; }
    public string Address { get; set; }
    public Uri Website { get; set; }
}

public class QualityProfile
{
    public int ID { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    /// <summary>
    /// Rank out of 1-10, 10 being the best
    /// </summary>
    public byte Ranking { get; set; }
}

public class GroceryCategory
{
    public int ID { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
}

這讓我想到了一個問題,我在GroceryItem類中擁有的SameItems的導航屬性是否足以表示多個雜貨項目的列表,或者這在引用自身時不起作用?

另外... CategoryQualityBestStore屬性是否需要ID屬性來表示GroceryItem類內部的外鍵(例如CategoryID),或者我用這種方法表示的方式還可以嗎?

- - 編輯 - -

-重構代碼-

我已根據以下建議對模型進行了重構,我認為它可以更好地適應您提出的建議(是第二次),意識到我的模型存在一些缺陷,並將價格成分提取到單獨的購買模型中。

public class GroceryItem
{
    public int ID { get; set; }
    public string Name { get; set; }

    [ForeignKey("Category")]
    public int CategoryID { get; set; }

    [ForeignKey("Quality")]
    public int QualityID { get; set; }

    //Navigation Properties
    public virtual QualityProfile Quality { get; set; }
    public virtual GroceryCategory Category { get; set; }
}

但是,我不確定哪個是本文的主題,如果我有一個集合作為模型的一部分(不像第一個示例那樣引用自身),我可以用一個表示嗎?導航屬性還是需要采取額外的步驟?

就是 如果我要在GroceryItem上允許多個不同的類別,而不是像這樣:

[ForeignKey("Category")]
public int CategoryID { get; set; }
public virtual GroceryCategory Category { get; set; }

它看起來像這樣:

public virtual ICollection<GroceryCategory> Categories { get; set; }

對於您的問題,最好的答案是“取決於情況”。 導航屬性是一種通知Entity Framework實體之間存在關系的方法。 按照慣例,如果您具有導航屬性,例如:

public Category Category { get; set; }

實體框架將在表上創建一個以[RelatedPropertyName]_[RelatedPK]形式命名的列。 對於您的類,上面的屬性將導致名為Category_ID的列。 您無需做任何其他工作即可使其工作。 EF將自動處理該關系。

但是,通過這種方式,您將無法訪問此外鍵屬性。 您的實體的公共API中沒有公開此內容。 通常,尤其是當從選擇列表中選擇相關項目以及類似的情況時,這變得很成問題,因為您必須將所選值存儲在其他位置,通常是視圖模型上的一個屬性,然后使用該屬性從數據庫中查詢相關內容。在將數據庫設置到它所屬的實體上並最終保存該實體之前。 鑒於具有實際的外鍵屬性,您可以直接將其直接發布回此屬性,而Entity Framework將自動連接相關實體。 因此,我傾向於始終將以下模式與導航屬性一起使用:

public int FooId { get; set; }
public virtual Foo Foo { get; set; }

在大多數情況下,Entity Framework會自動連接這兩者,以便FooId將保留Foo導航屬性的外鍵關系。 但是,有時,EF仍會跳閘並嘗試在幕后創建隱式外鍵,但是您可以通過明確告訴EF這是外鍵來糾正此行為:

[ForeignKey("Foo")]
public int FooId { get; set; }

集合導航屬性大致相同。 EF會將此視為存在一對多關系的指示,並在相反的實體上添加隱式外鍵。 鑒於您的收藏:

public virtual ICollection<GroceryItem> SimilarItems { get; set; }

相反的實體實際上是相同的實體,這提供了一個有趣的用例。 通常,EF將通過假設存在一對多關系來處理此問題。 您將在dbo.GroceryItems表上dbo.GroceryItems一列名為GroceryItem_ID的列。 不過,在這里,您不僅將無法直接訪問外鍵,而且也將無法訪問公用父API GroceryItem 這可能不是問題,但需要注意。 管理關系的唯一方法是通過父項上的集合,而不是通過該集合中的子項。

但是,由於這是自引用的,並且您沒有指定外鍵或實例導航屬性,因此所有EF都會看到的是關系雙方的集合,所以我的猜測是您最終會得到一個M2M中間表。 我目前無法自己驗證該理論,而且我自己之前也沒有嘗試過這種特殊情況。

要創建真正的一對多,您需要創建另一個導航屬性,類似於:

public virtual GroceryItem ParentGroceryItem { get; set; }

而且,即使如此,如果沒有一些Fluent配置,我也不認為EF可以解決問題:

HasMany(m => m.SimilarItems).WithOptional(m => m.ParentGroceryItem);

您也可以在其他情況下使用WithRequired代替WithOptional ,這顯然會使關系成為必需的關系,但是由於這是自引用的,因此不可能是必需的,因為必須至少有一個根節點且沒有父母

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM