【问题标题】:EF4 code-first: defining object relationships, foreign keysEF4 代码优先:定义对象关系、外键
【发布时间】:2011-05-15 23:35:42
【问题描述】:

EF 代码优先方法旨在节省大量时间,但目前我只看到玩具示例并花费数小时试图了解如何使其生成我想要的数据库。但仍然希望那个尤里卡时刻:-)

关于问题!

虚拟与具体属性

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

对象关系和外键

除了我感兴趣的“主要”属性 (public Person Owner { get; set; }) 之外,我找不到任何关于是否应该包含外键字段 (public int OwnerId { 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 的大脑有深入的最新参考,请也发布链接。

提前感谢您的宝贵时间!

【问题讨论】:

  • 代码优先旨在为您节省时间,如果您不太关心数据库的话。如果您想要精细控制,那么最好的方法是在 SQL Management Studio 中创建它并首先使用数据库来生成您的 EDMX。
  • 猜这取决于一个人对什么是“分钟控制”的看法 :-) 就我个人而言,我不关心列顺序和列名,但我确实想要一个高效且工程设计良好的数据库观点......如果我将来与我合作,我不会害怕。需要直接查询。但您的观点绝对正确,我同意 - CF 为我们提供了强大的工具,但也带走了一些控制权。
  • 我希望我能多次对此投票,尤其是咆哮。如果实际上约定没有以任何可参考的方式发布,我不确定如何按照约定操作代码。我在这里有一个小小的约定技巧,还有另一个。非常痛苦。
  • 感谢 Ralph,我不得不说感谢 SO 的一些乐于助人的人,我认为我经历了最糟糕的情况,并开始真正享受 EF4。在某个地方完整解释约定的观点仍然有效,我现在所知道的大部分内容都是来自 ScottGu 的各种帖子和其他博客的片段,这些片段通过反复试验痛苦地汇集在一起​​。希望进入 RTM 后情况会有所改善!
  • 喜欢这篇文章。我同意你们所有人的看法,我这周刚开始使用 EF4 + SQL CE4 并看到你在这里描述的每一个痛苦的步骤,没有一个帖子可以为你提供广泛的图片,只有很多类似的玩具样本。

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


【解决方案1】:

虚拟与最终属性:

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

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

外键关联或独立关联

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

检索时,myAccountInstanceFromDb.Owner 为空。这是为什么?如何告诉 EF 它应该发挥作用并填充我的 Owner 属性?

当然,您没有将其标记为虚拟,因此不支持延迟加载,但您也没有明确地预先加载或延迟加载它。要解决此问题,请使用 virtual 关键字并让 EF 为您延迟加载它,或者使用 Include 方法在整个对象物化时立即加载它。

标量属性与导航属性

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

【讨论】:

  • @Morteza,感谢您抽出时间再次回答我的基本问题——您真的是知识的拥护者! “始终将导航属性标记为虚拟被认为是一种好习惯” - 阅读了您的解释后,我现在明白了。问题是普通属性和导航属性之间的区别是什么 - 仅在对象中具有导航属性就足够了,还是需要由普通属性备份?
  • 换句话说,如果我有一个属于PersonAccount,为了定义它们之间的关系,我会:1)指定一个属性 int OwnerId导航属性 virtual Person Owner,或 2) 指定 属性 Person Owner,或 3) 指定 导航属性 @ 987654329@?
  • PS:我已经阅读了an explanation on MSDN,但我仍然不确定导航属性是否可以独立存在,或者它是否需要引用另一个对象本身的显式属性的支持/它的 FK。
  • 没问题,谢谢 :) 是的,导航属性可以独立存在,请参阅我对此主题的更新答案。
  • @Morteza,你又拯救了一天。当你对我说指针时,世界突然变得更加清晰易懂。我只希望至少有一些关于 EF 的文章遵循你的解释方式。从我的角度来看,主题已关闭 - 下一个见:-)
【解决方案2】:

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

你不需要添加外键字段 公共人员所有者 { 获取;放; } 将添加一个外键映射

【讨论】:

  • 感谢您的确认!但是,正如您从 .MapHierarchy 看到的那样,我需要手动执行此操作,因为我正在使用 TPT 策略。
猜你喜欢
  • 2018-05-31
  • 2011-07-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-08
相关资源
最近更新 更多