为什么在entity framework模型定义中为类属性使用“虚拟”?

在以下博客中: http : //weblogs.asp.net/scottgu/archive/2010/07/16/code-first-development-with-entity-framework-4.aspx

该博客包含以下代码示例:

public class Dinner { public int DinnerID { get; set; } public string Title { get; set; } public DateTime EventDate { get; set; } public string Address { get; set; } public string HostedBy { get; set; } public virtual ICollection<RSVP> RSVPs { get; set; } } public class RSVP { public int RsvpID { get; set; } public int DinnerID { get; set; } public string AttendeeEmail { get; set; } public virtual Dinner Dinner { get; set; } } 

在类中定义属性时使用virtual的目的是什么? 它有什么影响?

它允许entity framework围绕虚拟属性创build代理,以便该属性可以支持延迟加载和更有效的更改跟踪。 请参阅entity framework4.1 POCO代码优先,虚拟关键字有什么作用? 进行更彻底的讨论。

编辑澄清“创build一个代理”:通过“创build一个代理围绕”我具体指的是entity framework。 entity framework需要将您的导航属性标记为虚拟,以便支持延迟加载和有效的更改跟踪。 请参阅创buildPOCO代理的要求 。
entity framework使用inheritance来支持这个function,这就是为什么它需要某些属性在基类POCO中被标记为虚拟。 它从字面上创build派生自您的POCOtypes的新types。 所以你的POCO作为Entity Frameworkdynamic创build的子类的基types。 这就是我所说的“创build代理”的意思。

在运行时使用entity framework时,dynamic创build的entity framework创build的子类变得明显,而不是静态编译时。 只有当您启用entity framework的延迟加载或更改跟踪function。 如果您select不使用entity framework的延迟加载或更改跟踪function(这不是默认设置),那么您不需要将任何导航属性声明为虚拟。 然后,您负责自己加载这些导航属性,或者使用entity framework引用的“急切加载”,或者手动检索多个数据库查询中的相关types。 尽pipe如此,您可以也应该在许多场景中使用延迟加载和更改导航属性的跟踪function。

如果您要创build一个独立的类并将属性标记为虚拟,并且只需在您自己的应用程序中构build和使用这些类的实例(完全不在entity framework的范围之内),那么您的虚拟属性将无法为您带来任何收益拥有。

编辑来描述为什么属性将被标记为虚拟

属性如:

  public ICollection<RSVP> RSVPs { get; set; } 

不是田野,不应该这样想。 这些被称为getter和setter,在编译时被转换成方法。

 //Internally the code looks more like this: public ICollection<RSVP> get_RSVPs() { return _RSVPs; } public void set_RSVPs(RSVP value) { _RSVPs = value; } private RSVP _RSVPs; 

这就是为什么它们在entity framework中被标记为虚拟的,它允许dynamic创build的类覆盖内部生成的getset函数。 如果您的导航属性getter / setter在您的entity framework使用中为您工作,请尝试将其修改为属性,重新编译,并查看entity framework是否仍能正常工作:

  public virtual ICollection<RSVP> RSVPs; 

C#中的virtual关键字使得方法或属性可以被子类覆盖。 有关更多信息,请参阅关于“虚拟”关键字的MSDN文档

更新:很明显,我的回答并不符合预期的问题的情况下,但我会留在这里为任何人寻找一个简单的答案,原始的,非描述性的问题。

我理解OP的挫败感,虚拟的这种用法不适用于事实上的虚拟修饰符有效的模板抽象。

如果还有任何困难,我会提出我的观点,因为我试图保持解决scheme简单,行话最less:

entity framework在一个简单的部分确实使用延迟加载,这相当于为将来的执行做准备。 这符合“虚拟”修饰符,但还有更多。

在entity framework中,使用虚拟导航属性可以将其表示为SQL中等价的可为空的外键。 在执行查询时,您不必急于join每个键控表,但是当您需要这些信息时,它就变成了需求驱动。

我也提到可空,因为许多导航属性起初不相关。 即,在客户/订单情况下,您不必等待处理订单以创build客户。 你可以,但是如果你有一个多阶段的过程来实现这一点,你可能会发现需要坚持客户数据以便以后完成或部署到未来的订单。 如果所有导航属性都已经实现,则必须在保存中build立每个外键和关系字段。 这实际上只是将数据重新设置到内存中,从而破坏了持久性的作用。

所以,尽pipe在运行时的实际执行过程中可能看起来很模糊,但我发现使用的最佳经验法则是:如果要输出数据(读入View Model或Serializable Model)并且在引用之前需要值,则不要使用虚拟; 如果您的范围正在收集可能不完整的数据或者需要search而不需要search完成的每个search参数,则代码将充分利用引用,类似于使用可为空值的属性int? 长?。 另外,从数据收集中抽象出业务逻辑,直到需要注入它为止,具有许多性能优势,类似于实例化对象并以null开始。 entity framework使用了大量的reflection和dynamic,这可能会降低性能,需要一个可扩展到需求的灵活模型对于pipe理性能至关重要。

对我来说,总比使用像代理,代理,处理程序等超载的技术术语更有意义。 一旦你打到你的第三或第四编程语言,它可能会变得凌乱。

将模型中的导航属性定义为虚拟是相当常见的。 当导航属性被定义为虚拟时,它可以利用某些entity frameworkfunction。 最常见的是懒加载。

延迟加载是许多ORM的一个很好的function,因为它允许您dynamic地访问模型中的相关数据。 在实际访问之前,不会不必要地获取相关数据,从而减less了对数据库数据的前期查询。

从“使用Bootstrap和Knockout.js的ASP.NET MVC 5”