我记得EF navigation property should be virtual:
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<Post> 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<Enrollment> Enrollments { get; set; }
}
不再需要了吗?
答案 0 :(得分:52)
virtual
从未必需。只有在您需要延迟加载支持时才需要它。
自Lazy loading is not yet supported by EF Core以来,目前virtual
没有特殊含义。它会(以及如果)添加延迟加载支持(这样做有plan)。
更新:从EF Core 2.1开始,现在支持Lazy loading。但是,只要您不添加Microsoft.EntityFrameworkCore.Proxies包并通过UseLazyLoadingProxies
启用它,原始答案仍然适用。
但是,如果您这样做,由于初始实施中缺少选择加入控制,事情会完全改变 - 需要 所有您的导航属性virtual
。这对我来说没有意义,你最好不要使用它,直到它得到修复。如果您确实需要延迟加载,请使用替代Lazy loading without proxies
方法,在这种情况下virtual
再次无关紧要。
答案 1 :(得分:18)
自从接受了答案后,情况发生了变化。在2018年,Lazy Loading is now supported as of Entity Framework Core 2.1有两种不同的方法。
两者的简单方法是使用代理,这将要求使用virtual
来延迟加载所需的属性。引用链接页面:
使用延迟加载的最简单方法是安装Microsoft.EntityFrameworkCore.Proxies包并通过调用
UseLazyLoadingProxies
启用它。 [...]然后,EF Core将为任何可以覆盖的导航属性启用延迟加载 - 也就是说,它必须是虚拟的,并且可以继承自可以继承的类。
以下是提供的示例代码:
public class Blog
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Post> 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
注入到数据类型的构造函数中。 This is explained in here
简而言之,有两种方法可以执行延迟加载:使用和不使用代理。 virtual
必需当且仅当您希望支持使用代理进行延迟加载时。否则,它不是。
答案 2 :(得分:15)
虚拟关键词从未被要求......它是可选的。
它有什么变化?
<强> 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;
答案 3 :(得分:3)
在EF Core中,默认情况下选择了阻止延迟加载的路径。 此外,我认为在此问题之后仍未实现此功能。
https://github.com/aspnet/EntityFramework/issues/3312
使用以前版本的EF,虚拟导航属性允许延迟加载相关实体。
我想现在只能使用.Include(...)
编辑:
有几种方法可以加载Core支持的相关实体。 如果您有兴趣:https://docs.microsoft.com/en-us/ef/core/querying/related-data
答案 4 :(得分:1)
更新:计划用于EF Core 2.1的延迟加载的初始实现将要求将导航属性声明为虚拟。请参阅https://github.com/aspnet/EntityFrameworkCore/issues/10787,更一般地说,要跟踪延迟加载的进度,请参阅https://github.com/aspnet/EntityFrameworkCore/issues/10509。
答案 5 :(得分:0)
如果您定义虚拟的导航属性,则Entity Framework将在运行时创建一个从您的类派生的新类(动态代理),并使用它代替原始类。这个新动态创建的类包含用于在首次访问时加载导航属性的逻辑。这称为“延迟加载”。它使Entity Framework避免加载数据库中不需要的整个依赖对象树。 https://dipoletechi.com/blog-post/virtual-in-entity-framework/ 问候 阿坎沙