导航属性应该是虚拟的 – 在ef核心中不需要?

我记得在EF 导航属性应该是虚拟的 :

public class Blog { public int BlogId { get; set; } public string Name { get; set; } public string Url { get; set; } public string Tags { get; set; } public virtual ICollection Posts { get; set; } } 

但我看看EF Core并不认为它是虚拟的:

 public class Student { public int ID { get; set; } public string LastName { get; set; } public string FirstMidName { get; set; } public DateTime EnrollmentDate { get; set; } public ICollection Enrollments { get; set; } } 

它不再需要了吗?

EF中从未需要 virtual 。 只有在您需要延迟加载支持时才需要它。

由于EF Core尚不支持延迟加载 ,因此当前virtual没有特殊含义。 它会(以及如果)添加延迟加载支持(有这样做的计划 )。

更新:从EF Core 2.1开始,现在支持延迟加载 。 但是,只要您不添加Microsoft.EntityFrameworkCore.Proxies包并通过UseLazyLoadingProxies启用它,原始答案仍然适用。

但是,如果这样做,由于初始实现中缺少选择加入控制,事情会完全改变 – 它要求 所有导航属性都是virtual 。 这对我来说没有意义,你最好不要使用它,直到它得到修复。 如果你真的需要延迟加载,请使用替代的Lazy加载而不使用代理方法,在这种情况下, virtual无关紧要。

自从接受了答案后,情况发生了变化。 在2018年,对于两种不同的方法, 现在支持entity framework核心2.1的延迟加载 。

两者的简单方法是使用代理,这将需要延迟加载的属性用virtual定义。 要从链接页面引用:

使用延迟加载的最简单方法是安装Microsoft.EntityFrameworkCore.Proxies包并通过调用UseLazyLoadingProxies启用它。 […]然后,EF Core将为任何可以覆盖的导航属性启用延迟加载 – 也就是说,它必须是虚拟的,并且可以inheritance自可inheritance的类。

以下是提供的示例代码:

 public class Blog { public int Id { get; set; } public string Name { get; set; } public virtual ICollection Posts { get; set; } } public class Post { public int Id { get; set; } public string Title { get; set; } public string Content { get; set; } public virtual Blog Blog { get; set; } } 

还有另一种不使用代理进行延迟加载的方法, ILazyLoader注入数据类型的构造函数。 这在这里解释 。

简而言之,有两种方法可以执行延迟加载:使用和不使用代理。 当且仅当您希望支持使用代理进行延迟加载时,才需要 virtual 。 否则,事实并非如此。

虚拟关键词从未被要求……它是可选的。

它有什么变化?

1.如果您宣布您的财产是虚拟的:

查询主对象时,不会立即加载您的虚拟属性(默认情况下)。 只有当您尝试访问它或访问其中一个组件时,它才会从数据库中进行检索。

这称为延迟加载。

2.如果你声明它是非虚拟的:

您的财产将(默认情况下)立即加载到您的主要实体中的所有其他财产。 这意味着您的财产将可以访问:它已经被检索。 实体不必再次查询数据库,因为您访问此属性。

这被称为急切加载。

我的看法 :

更常见的是我选择急切加载(非虚拟),因为大多数时候,我需要使用每个实体的每个属性而不必回复(在你真的想要快速的一切的情况下更快)但是如果你访问这个属性偶尔只有一次(你没有列出任何东西),而你想要更多地通常只有其余的信息来自这个,然后使它成为虚拟,所以这个属性不会减慢查询的其余部分只是为了一些访问。

希望这很清楚……

例子:

我不会使用虚拟(热切):

 foreach(var line in query) { var v = line.NotVirtual; // I access the property for every line } 

我将使用虚拟或延迟加载:

 foreach(var line in query) { if(line.ID == 509) // because of this condition var v = line.Virtual; // I access the property only once in a while } 

最后一件事 :

如果您不查询超过1 000行的数据库,那么您选择的任何内容都不会产生很大影响。 此外,您可以声明这些属性是虚拟的,如果您想要反过来测试,您只需执行此操作(实体4.0):

 context.LazyLoadingEnabled = false; 

它将取消虚拟效果。

编辑

对于较新版本的EF:

 WhateverEntities db = new WhateverEntities() db.Configuration.LazyLoadingEnabled = false; 

在EF Core中,默认情况下选择了阻止延迟加载的路径。 此外,我认为此function在此问题后仍未实现。

https://github.com/aspnet/EntityFramework/issues/3312

使用以前版本的EF,虚拟导航属性允许延迟加载相关实体。

我想现在加载导航属性只能用.Include(...)

编辑:

有几种方法可以加载Core中支持的相关实体。 如果您有兴趣: https : //docs.microsoft.com/en-us/ef/core/querying/related-data

更新:计划用于EF Core 2.1的延迟加载的初始实现将要求将导航属性声明为虚拟。 请参阅https://github.com/aspnet/EntityFrameworkCore/issues/10787 ,更一般地说是跟踪延迟加载的进度,请参阅https://github.com/aspnet/EntityFrameworkCore/issues/10509 。