Entity Framework Core - 延迟加载

51

考虑到我的Visual Studios要求,我使用Entity Framework Core (1.0.1)开始了我的最新项目。

因此,我像以往一样编写我的数据库模型,使用“virtual”关键词为列表启用延迟加载。但是,在加载父表时,子列表似乎从未加载。

父模型

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记录嵌套在Events记录内一样将其作为列表嵌套。

可是当我查询这个表时

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

问题

无论后台数据如何,EventInclusions都将返回一个空值。

阅读一些内容后,我感觉这是EF6和我通常使用的EF Core之间的改变。

我可以使用一般性的延迟加载语句,或者找出指定延迟加载的新格式,寻求帮助。

Caz


你在上下文中启用了延迟加载吗? - Gusman
1
嘿Gusman,我以前从未需要在EF6中使用 - 我猜这可能是问题所在,因为我的上下文中没有与延迟加载相关的内容。 - Caz1224
如果他们保留了相同的机制(我还没有在核心中使用EF),那么您必须在上下文的构造函数中设置 Configuration.LazyLoadingEnabled = true;Configuration.ProxyCreationEnabled = true; - Gusman
3
EF Core目前不支持自动延迟加载。 - Hamid Pourjam
是的,"dotctor" 是正确的:https://docs.efproject.net/en/latest/querying/related-data.html - Gusman
3
这篇文章很好,但读起来会感到痛苦......我现在百分之百后悔升级了! - Caz1224
7个回答

41

有没有一种简单的方法来生成支持延迟加载的 EF 模型?因为它需要将导航属性设置为虚拟属性... - juliushuck
1
没关系。我可以从数据库更新模型,并生成虚拟的导航属性。 - juliushuck
1
你怎么关闭它? - Christian Findlay
@MelbourneDeveloper,我的理解是默认情况下懒加载是关闭的。如果您想要加载更多数据,我使用.Include()调用来加载我需要的嵌套数据,如此处所示:https://learn.microsoft.com/en-us/ef/core/querying/related-data#eager-loading - Elijah Lofgren
@huckjulius 你能用 dotnet ef dbcontext scaffold 生成虚拟导航属性吗?它会把 virtual 关键字删除掉。 - Victor Mota

37

看起来 EF Core 目前不支持延迟加载,虽然正在推出中,但可能还需要一段时间。

目前,如果有人遇到此问题并且遇到困难。下面是使用 急切加载 的示例,这是目前你必须使用的方法。

以前,你可能有一个包含另一个表中 Hat 列表的 Person 对象。

不要写成:

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=> 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();

我有点理解为什么这种方法更安全,因为你不会加载可能会拖慢速度的大数据集。但我希望他们尽快恢复懒加载功能!!!

Caz


7
你知道如何在需要加载导航属性时实现仓储模式吗?当你需要未知数量的include函数时,这并不容易...有任何想法吗?请注意,我会尽最大努力让翻译通俗易懂,但不改变原意。 - Mohammed Noureldin
1
@MohammedNoureldin 我也遇到了同样的问题。最后我通过暴露IQueryable来“解决”它。例如,现在我的存储库上有像 IQueryable<T> GetByIdQueryable(string id) 这样的方法。调用者可以执行 _repo.GetByIdQueryable(id) .Include(b => b.RelatedEntityProperty) .SingleOrDefault(); 它起作用,即使在单元测试中也没问题,但对我来说,这有点让人不舒服,因为你必须以这种方式公开它。另一个选择是传递你想要包含的属性的字符串名称,但我认为那只是在招麻烦。 - Steve
对于多层级的包含(“还有那些帽子上的羽毛”),可以使用 .ThenInclude() - Hans Kesting
包含似乎对于大表格来说需要消耗很多时间。或许最好放弃懒加载。 - nam vo
如果Include花费太多时间,我建议您查看数据库结构。如果数据库被正确索引和规范化,那么情况不会太糟糕。 - Caz1224
过时的答案。现在已经支持懒加载。 - Daniel Hillebrand

32

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

Microsoft.EntityFrameworkCore.Proxies

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

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

请注意,此软件包仅适用于 EF Core 2.1 及以上版本。


12

对于 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中无法关闭惰性加载: https://github.com/aspnet/EntityFrameworkCore/issues/15802 - Christian Findlay
options.UseLazyLoadingProxies(false); 在我的电脑上禁用了 LazyLoading。 - Kowi

7

最新的一个预发布版本刚刚发布,虽然不久将以完整版的形式发布。

需要注意以下几点:

  • All your data properties that are more than simple types (ie: any other classes/tables) need to be public virtuals (default scaffolding they're not).
  • This line gets tucked into OnConfiguring on your data context:

        optionsBuilder.UseLazyLoadingProxies();
    
  • It's (currently) pre-release so may the force be with you.

5

1
请做一些支持EF Core 2.0的工作。 - Jins Peter

3

懒加载计划于EF core 2.1中推出 - 您可以在此处阅读有关为什么它是必备功能的更多信息-这里


链接失效,修复后需要登录。是否有公开的源代码? - Isaac Llopis
链接已修复:D 谢谢您让我知道。一旦懒加载到达EF7,它将是可用的...等待了将近一年... - baHI
我尝试了一下,发现速度太慢了,所以最好还是放弃懒加载。https://wildermuth.com/2018/07/28/Avoid-Lazy-Loading-in-ASP-NET - nam vo
它取决于你如何使用它。惰性加载和N+1查询是常见问题。如果我们事先知道我们需要什么,就可以避免这种情况。在支持惰性加载之前,EF Core的主要问题是无法区分空值还是未加载的N:1引用(缺少代理,没有DataNotLoadedException)。这就像骑自行车一样,只因为你开车,并不意味着其他人永远不应该骑自行车。 - baHI

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接