Entity Framework Core - 延迟加载

Posted

技术标签:

【中文标题】Entity Framework Core - 延迟加载【英文标题】:Entity Framework Core - Lazy Loading 【发布时间】:2017-02-28 13:10:34 【问题描述】:

应我的 Visual Studios 请求,我使用 Entity Framework Core (1.0.1) 开始了我的最新项目

所以编写我的数据库模型,因为我一直使用“虚拟”说明符来启用列表的延迟加载。虽然在加载父表时,子列表似​​乎永远不会加载。

父模型

public class Events

    [Key]

    public int EventID  get; set; 
    public string EventName  get; set; 
    public virtual List<EventInclusions> EventInclusions  get; set; 

儿童模型

public class EventInclusions

    [Key]
    public int EventIncSubID  get; set; 
    public string InclusionName  get; set; 
    public string InclusionDesc  get; set; 
    public Boolean InclusionActive  get; set; 


向这些表中添加新记录似乎很有效,因为我习惯了可以将 EventInclusions 记录作为列表嵌套在事件记录中的位置。

虽然当我查询这张表时

_context.Events.Where(e => e.EventName == "Test")

问题

无论幕后的数据如何,EventInclusions 都会返回一个空值。

读了一点之后,我感觉这是我通常使用的 EF6 和 EF Core 之间的变化

我可以使用一些帮助来制作一揽子延迟加载声明或找出指定延迟加载的新格式。

卡兹

【问题讨论】:

您是否在上下文中启用了延迟加载? 嘿,Gusman,我在 EF6 中从来不需要这样做 - 我猜这可能是问题所在,因为在我的上下文中我与延迟加载无关 如果它们保留了相同的机制(我仍然没有将 EF 与核心一起使用),那么您必须在上下文的构造函数上设置 Configuration.LazyLoadingEnabled = true;Configuration.ProxyCreationEnabled = true; EF Core 目前不支持自动延迟加载 这是一本好书,但读起来很痛苦……现在 100% 后悔升级了! 【参考方案1】:

EF Core 2.1 现在提供延迟加载,这里是相关文档的链接:

https://docs.microsoft.com/en-us/ef/core/querying/related-data#lazy-loading

【讨论】:

有没有一种简单的方法来生成延迟加载的 ef 模型?因为它要求导航属性是虚拟的... 没关系。我可以从数据库中更新模型并生成虚拟导航属性。 如何关闭它? @MelbourneDeveloper,我的理解是默认情况下延迟加载是关闭的。如果您想要加载更多数据,我使用 .Include() 调用来加载我需要的嵌套数据,如下所示:docs.microsoft.com/en-us/ef/core/querying/… @huckjulius 你能使用dotnet ef dbcontext scaffold 生成虚拟导航属性吗?它正在为我删除 virtual 关键字。【参考方案2】:

看来 EF Core 目前不支持延迟加载。它即将到来,但可能需要一段时间。

现在,如果其他人遇到这个问题并且正在苦苦挣扎。下面是使用 Eager loading 的演示,这是您现在必须使用的。

假设你有一个人对象并且该对象在另一个表中包含一个帽子列表。

而不是写

var person = _context.Person.Where(p=> p.id == id).ToList();

person.Hats.Where(h=> h.id == hat).ToList();

你需要写

var person = _context.Person.Include(p=> p.Hats).Where(p=> p.id == id).ToList();

然后person.Hats.Where(h=&gt; h.id == hat).ToList(); 将起作用

如果您有多个列表 - 链接包含

var person = _context.Person.Include(p=> p.Hats).Include(p=> p.Tickets)
                            .Include(p=> p.Smiles).Where(p=> p.id == id).ToList();

我有点明白为什么这种方法更安全,因为您不会加载可能会减慢速度的庞大数据集。但我希望他们能尽快恢复延迟加载!!!

卡兹

【讨论】:

当我必须急切加载导航属性时,您知道如何实现存储库模式吗?当您需要未知数量的 include 函数时,这根本不容易……有什么想法吗? @MohammedNoureldin 我遇到了同样的问题。最后,我通过简单地公开 IQueryable 来“解决”它。例如现在,我的存储库中有 IQueryable GetByIdQueryable(string id) 方法之类的东西。然后调用者可以执行 _repo.GetByIdQueryable(id) .Include(b => b.RelatedEntityProperty) .SingleOrDefault();它可以工作,甚至可以用于单元测试,但对我来说,你必须以这种方式公开它有点味道。另一种选择是传递要包含的属性的字符串名称,但这只是在自找麻烦。 对于多个级别的包含(“还有那些帽子上的羽毛”),有.ThenInclude() include 似乎为大表消耗了很多时间。也许只是忘记延迟加载。 如果 Include 花费了太多时间,我建议查看您的数据库结构。如果数据库被正确索引和规范化,它应该不会那么糟糕。【参考方案3】:

您可以安装此包以在 EF Core 2.1 中启用延迟加载。

Microsoft.EntityFrameworkCore.Proxies

然后在你的 ef dbContext 中设置这个配置

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
     => optionsBuilder
           .UseLazyLoadingProxies()
           .UseSqlServer("myConnectionString");

“注意”此包仅适用于 EF Core 2.1 及更高版本。

【讨论】:

【参考方案4】:

对于 EF Core 2.1 及更高版本,

安装:

 dotnet add package Microsoft.EntityFrameworkCore.Proxies --version 2.2.4 

然后如下所示更新您的 Startup.cs 文件。

using Microsoft.EntityFrameworkCore.Proxies;



services.AddEntityFrameworkProxies();
services.AddDbContext<BlogDbContext>(options =>
            
                options.UseSqlite(Configuration.GetSection("ConnectionStrings")["DefaultConnection"]);
                options.UseLazyLoadingProxies(true);
            );

【讨论】:

这看起来很有帮助,所以我尝试了它,但它不起作用。我认为 EF Core 中无法关闭延迟加载:github.com/aspnet/EntityFrameworkCore/issues/15802 options.UseLazyLoadingProxies(false);在我的机器上禁用了 LazyLoading。【参考方案5】:

pre-release version 刚刚发布,尽管它应该很快就会完整发布。

几个注意事项:

您所有不只是简单类型的数据属性(即:任何其他类/表)都必须是公共虚拟对象(它们不是默认脚手架)。

这一行被塞进你的数据上下文的 OnConfiguring 中:

    optionsBuilder.UseLazyLoadingProxies();
它(当前)是预发布的,所以可能会与你同在。

【讨论】:

【参考方案6】:

EF Core 尚不支持 LazyLoading,但有一个非官方的库可以启用 LazyLoading:https://github.com/darxis/EntityFramework.LazyLoading。在正式支持之前,您可以使用它。 它支持 EF Core v1.1.1。它以 nuget 包的形式提供:https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.LazyLoading/

免责声明:我是此 repo 的所有者,并邀请您试用、报告问题和/或贡献。

【讨论】:

请做一些事情来支持 EF core 2.0【参考方案7】:

延迟加载计划在 EF 核心 2.1 中提供 - 您可以阅读更多关于它为什么是必备功能的信息 - here。

【讨论】:

链接损坏,修复后需要登录。有公开的来源吗? 链接已修复:D 感谢您让我知道。延迟加载到 EF7 后,就可以使用了……等了将近一年…… 我试过了,觉得太慢了,还是先跳过懒加载吧。 wildermuth.com/2018/07/28/Avoid-Lazy-Loading-in-ASP-NET 这就是你使用它的方式。延迟加载和 n+1 选择是一个常见问题。如果我们提前知道我们需要什么,就会避免它。在支持延迟加载之前,EF 核心的一个大问题是它无法判断您是否有一个空值或只是一个未加载的 n:1 引用(缺少代理,没有 datanotloadedexception)。就像自行车一样,仅仅因为您使用汽车,并不意味着其他人不应该骑自行车。

以上是关于Entity Framework Core - 延迟加载的主要内容,如果未能解决你的问题,请参考以下文章

Entity Framework Core 快速开始

EF6 System.Data.Entity.Core.EntityKey 在 Entity Framework Core 中的等价物是啥?

张高兴的 Entity Framework Core 即学即用:创建第一个 EF Core 应用

Entity Framework Core 迁移命令

Entity Framework Core - 计算字段排序

Entity Framework Core 性能优化