实体框架 - 急切加载虚拟集合的相关记录

问题描述 投票:0回答:2

迁移到 EF6 后,我希望能够利用预先加载来迭代实体的相关记录的虚拟集合,以确保根据需要获得最佳查询效率。但是,当尝试在虚拟集合上使用

Include
急切加载功能时,这不起作用。

由于访问这些虚拟集合会导致数据库查询延迟加载,因此我认为会有一些控制这些查询的能力。

考虑以下定义:

class Group
{
    public virtual ICollection<Member> Members {get;set;}
}
class Member
{
    public int ID {get;set;}
    public virtual User User {get;set;}
}
class User
{
    public int ID {get;set;}
    ...
}

我需要查询组的所有成员以及每个关联的用户,而不是懒惰且低效地分别查询每个用户。我尝试在允许并检索数据的虚拟

Include
上使用
ICollection
,但仍然使用延迟加载而不是急切加载。

var members = group.Members.Include(m => m.User);

我可以想象,使用

ICollection
实现这些相关实体可能是出于良好的抽象原因。因此,它们似乎不是公开查询功能的明显位置。但事实是,使用这些虚拟属性是与数据库记录的相关对象交互的主要方式。由于这会导致查询,开发人员应该能够在需要时优化它们。

Include
目前仅对
IQueryable
对象起作用。在
AsQueryable
上调用
ICollection
也不起作用。实现我需要的唯一方法是从头开始构建查询。

using (var db = Context()) 
{
    var memberIds = group.Members.Select(m => m.ID);
    db.Members.Include(m => m.User).Where(m => memberIds.Includes(m.ID));
}

有谁知道在优化急切加载的同时使用虚拟道具和集合的更简单方法?我想

ICollection
上的自定义扩展应该可以按照我想要的方式使用它。

c# .net entity-framework
2个回答
1
投票

无法将实体的虚拟集合与 Include 功能一起使用

经过一番讨论才弄清楚你的意思。

鉴于...

group.Members.Include(m => m.User);

...

group
是一个
Group
对象,之前从数据库中提取出其
Members
并由
Include
急切加载,您期望上面的语句可用于加载每个成员的
User 
财产。

当然,那太好了,但是...

  • 文档中说

    您可以使用

    Include
    方法指定查询结果中包含的相关数据。

    也许它不够突出,但“在查询结果中”意味着

    Include
    适用于查询,即
    IQueryable
    。您发现这一点是因为上面的语句无法编译。它在使用
    group.Members.AsQueryable
    时编译,但随后
    Include
    什么也不做,因为
    AsQueryable
    创建了一个没有
    Include
    实现的对象。解释所有这些需要太多的时间,但足以说明
    group
    只是一个普通的 C# 对象,不知道它是由什么创建的。它与 EF 的查询提供程序没有联系,该查询提供程序可以生成用于加载嵌套对象的查询,并且
    AsQueryable
    不会“注入”此查询提供程序。 (即便如此,也很难有效地做到这一点)。

  • 假设可以。那么它就不会依赖于属性是否

    virtual
    。就像常规的
    Inlude
    方法加载虚拟和非虚拟属性一样。

  • 它不会像你期望的那样工作。您似乎希望

    group.Members.Include(m => m.User)
    当场加载所有
    User
    对象。但 EF 的
    Include
    方法不会 execute 预加载,它只是 species 它。它通过指令修改
    IQueryable
    以立即加载嵌套数据。但
    IQueryable
    本身不执行任何操作,仅在强制执行时返回数据(称为 延迟执行)。

所以你要么应该

Include
从一开始就成为用户,比如......

db.Groups.Include(g => g.Members).ThenInclude(m => m.User)

...或者让延迟加载完成其工作,但正如您所说,这是低效的,因为它为每个

User
对象运行一个查询。

总结

是的,如果能够有效地将对象图进一步扩展一层的功能就太好了。我只是不明白 EF 如何能够如此轻松地实现,或者根本不明白。


0
投票

当你有两个模型并且模型之间存在关系时。像这样:

public class User
{
    public int Id { get; set; }
    
    public string Name { get; set; }
}

public class Member 
{
    public int Id { get; set; }
    
    public int UserId { get; set; }

    public User User { get; set; }
}

如果您加载成员而不包含成员。用户为空

如果您使用包含具有此条件的用户

User.Id == Member.UserId
加载并在member.User中设置

var member = dbContext.Members.Include(m => m.User).First();

当您使用 include 时,EF 会生成 sql 查询:

select top 1 m.*, u.*
from Members m
join users u on u.Id = m.UserId
© www.soinside.com 2019 - 2024. All rights reserved.