< 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的大脑有一个深入的最新参考,也请发布链接。
提前感谢您的时间!
答案 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;组;将添加一个外键映射