![](/img/trans.png)
[英]Can I have navigation properties based on certain fields (not primary keys!, unique or foreign keys)?
[英]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的导航属性是否足以表示多个杂货项目的列表,或者这在引用自身时不起作用?
另外... Category , Quality和BestStore属性是否需要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.