导航属性应该是虚拟的 – 在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 。