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

Dav*_*Dav 17 .net mapping entity-relationship entity-framework 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为了使延迟加载成为可能(正确...?),但这在非集合的世界中如何应用?

对象关系和外键

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

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

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

异物,外键 - 继续

正如我上面提到的,即使我只public Person Owner { get; set; }在我的对象中(例如Event),该表Events将包含Owner_Id由EF自动添加的列.更重要的是,在检索时,我将可以访问属性Owner.

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

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

public class OpenIdAccount : Account
{
    public string Identifier { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我希望他们与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");
Run Code Online (Sandbox Code Playgroud)

您可能会注意到,我尝试重新创建EF对我的Owner_Id列所做的事情.但在检索时,myAccountInstanceFromDb.Owner为空.这是为什么?我怎么告诉EF它应该发挥它的魔力并填充我的Owner财产?

指针,指针

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

提前谢谢您的时间!

Mor*_*avi 9

虚拟与最终属性:

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

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

外国人协会或独立协会

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

检索后,myAccountInstanceFromDb.Owner为null.这是为什么?我怎么告诉EF它应该做它的魔术并填充我的所有者属性?

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

标量属性与导航属性

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