EF4代码优先:定义对象关系,外键

时间:2010-11-26 01:33:23

标签: .net entity-framework mapping entity-relationship code-first

< RANT_MODE>

EF代码优先方法是为了节省大量时间,但目前我只看过玩具示例,花了好几个小时试图了解如何让它生成我想要的数据库。但仍然希望尤里卡时刻: - )

< RANT_MODE />

关于问题!

虚拟与具体属性

我正在尝试了解EF如何映射和检索对象关系。我什么时候应该将房产标记为virtual,何时不标记? (在public Person Owner { get; set; }public virtual Person Owner { get; set; }中一样。)在代码优先的几十个例子中,我看到他们似乎可以互换地使用这些,但没有太多解释。我所知道的是导航属性(public virtual ICollection<Person> Owners { get; set; })需要virtual才能使延迟加载成为可能(正确...?),但这在非集合的世界中如何应用?

对象关系和外键

除了我感兴趣的'main'属性(public int OwnerId { get; set; })之外,我无法找到关于是否应该包含外键字段(public Person Owner { get; set; })的任何信息。我尽力不去,EF在我的表中自动添加了一个名为Owner_Id的int列,似乎理解了我的意图。

Conventions for Code First(“外键”部分)中,EF团队提到“在关系的依赖端包含外键属性是很常见的”,并且“Code First现在将推断任何名为''(即OwnerId)[...]的属性与主键具有相同的数据类型,表示关系的外键“。 IE浏览器。如果我有两个EF会知道他们是相关的。

但除了“异物”本身之外,明确指定持有FK的此类属性是否被视为良好做法?

异物,外键 - 续

正如我上面提到的,即使我的对象中只有public Person Owner { get; set; }(例如Event),表格Events也会以EF自动添加的Owner_Id列为特色。更重要的是,在检索后,我将可以访问Owner的属性。

但是,请考虑以下方案。我有两节课:

public class Account
{
    public int Id { get; set; }
    public Person Owner { get; set; }
}

public class OpenIdAccount : Account
{
    public string Identifier { get; set; }
}

我希望它们与TPT相关。这意味着手动映射:

modelBuilder.Entity<Account>().MapHierarchy(a => new
{
    a.Id, 
    Owner_Id = a.Owner.Id
}).ToTable("Account");

modelBuilder.Entity<OpenIdAccount>().MapHierarchy(a => new
{
    a.Id,
    a.Identifier
}).ToTable("OpenIdAccount");

您可能会注意到,我尝试重新创建EF对Owner_Id列的影响。但是在检索时,myAccountInstanceFromDb.Owner为空。这是为什么?如何告诉EF它应该发挥作用并填充我的Owner属性?

指针,指针

如果你能澄清上述内容,我将非常感激 - 到了真正希望知道答案的地步,但又无法阅读另一篇文章,仅仅展示了另一个玩具示例,说明与EF一起玩是多么容易。也就是说,如果你对EF的大脑有一个深入的最新参考,也请发布链接。

提前感谢您的时间!

2 个答案:

答案 0 :(得分:9)

虚拟与最终属性:

这首先与代码无关,它是EF和POCO的主题:当您拥有POCO时,您会失去对导航属性的大量EF支持,您可以通过将它们设置为虚拟来选择加入它们。这使EF可以在运行时创建代理,并通过覆盖该代理类中的导航属性来为您提供支持。这些支持是更改通知关系修复延迟加载

延迟加载对Collection和非Collection类型导航属性的工作方式相同。此外,它也被视为良好做法,始终将您的导航属性标记为虚拟。

外国人协会或独立协会

EF3.5不支持关联中的FK并使其隐藏(a.k.a 独立关联)。 EF4开始支持协会中的FK(a.k.a 外键协会)。取决于您喜欢哪一个,您可以明确包含或不包含FK属性,但除了导航属性之外,明确指定FK属性绝对是一个好习惯,因为它为您提供了使用对象的最大灵活性。

  

检索后,myAccountInstanceFromDb.Owner为空。这是为什么?我如何告诉EF它应该发挥它的魔力并填充我的所有者属性?

当然,您没有将其标记为虚拟,因此不支持延迟加载,但您没有明确地急切加载或延迟加载它。要解决此问题,请使用虚拟关键字并让EF延迟加载它,或者使用包含方法在整个对象实现时急切加载它。

标量属性与导航属性

标量属性是属性,其值实际上包含在实体中并与表列对应(例如Account.Id)。
导航属性仅仅是相关实体的指针。例如,Account实体具有Owner属性,该属性将使应用程序能够从Account导航到拥有该Account的所有者。
所以,回到你的问题,你需要做的就是将导航属性指定为virtual Person Owner可选将FK属性指定为int OwnerId,你就可以了。

答案 1 :(得分:0)

标记虚拟属性会使相关对象被调用延迟

您无需添加外键字段 公共人物所有者{get;组;将添加一个外键映射