实体框架6:即使在查询中显式加载,也会延迟加载虚拟集合

jpa*_*aya 5 c# linq entity-framework

尝试优化查询时,我遇到EF6问题.考虑这个有一个集合的类:

public class Client
{
    ... a lot of properties
    public virtual List<Country> Countries { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

您可能知道,使用延迟加载我有这个n + 1问题,当EF试图为每个客户端获取所有国家/地区时.

我试图使用Linq投影; 例如:

        return _dbContext.Clients
            .Select(client => new
            {
                client,
                client.Countries
            }).ToList().Select(data =>
            {
                data.client.Countries = data.Countries; // Here is the problem
                return data.client;
            }).ToList();
Run Code Online (Sandbox Code Playgroud)

这里我使用两个选择:第一个用于Linq投影,因此EF可以创建SQL,第二个用于将结果映射到Client类.原因是因为我正在使用一个返回的存储库接口List<Client>.

尽管查询是使用其中的国家生成的,但当我尝试渲染整个信息时,EF仍在使用延迟加载(相同的n + 1问题).避免这种情况的唯一方法是删除虚拟访问器:

public class Client
{
    ... a lot of properties
    public List<Country> Countries { get; set; } 
}
Run Code Online (Sandbox Code Playgroud)

我对此解决方案的问题是我们仍然希望将此属性设置为虚拟.此优化仅对应用程序的特定部分是必需的,而在其他部分我们希望具有此延迟加载功能.

我不知道如何"通知"EF关于这个属性,这个属性已经通过这个Linq投影延迟加载了.那可能吗?如果没有,我们还有其他选择吗?的n + 1个问题使得应用到需要几秒钟来加载像1000行.

编辑

谢谢你的回复.我知道我可以使用Include()扩展来获取集合,但我的问题是需要添加一些额外的优化(我很抱歉没有发布完整的示例,我认为收集问题就足够了):

public class Client
{
    ... a lot of properties
    public virtual List<Country> Countries { get; set; }
    public virtual List<Action> Actions { get; set; }
    public virtual List<Investment> Investments { get; set; }
    public User LastUpdatedBy {
        get {
          if(Actions != null) {
              return Actions.Last();
          }       
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我需要渲染客户端,有关上次更新的信息和投资数量(Count()),Include()我实际上需要从数据库中获取所有信息.但是,如果我使用像投影一样

        return _dbContext.Clients
              .Select(client => new
              {
                    client,
                    client.Countries,
                    NumberOfInvestments = client.Investments.Count() // this is translated to an SQL query
                    LastUpdatedBy = client.Audits.OrderByDescending(m => m.Id).FirstOrDefault(),
              }).ToList().Select(data =>
              {
                    // here I map back the data
                    return data.client;
              }).ToList();
Run Code Online (Sandbox Code Playgroud)

我可以减少查询,只获取所需的信息(在LastUpdated的情况下,我需要将属性更改为getter/setter,这不是一个大问题,因为它仅用于应用程序的这个特定部分).

如果我使用这种方法的Select()(投影然后映射),Include()EF不考虑该部分.

Eld*_*dho 1

如果我理解正确的话你可以试试这个

_dbContext.LazyLoading = false;

var clientWithCountres =  _dbContext.Clients
                                    .Include(c=>c.Countries)
                                    .ToList();
Run Code Online (Sandbox Code Playgroud)

这将获取Client并仅包含它Countries。如果禁用延迟加载,则不会从查询中加载其他集合。除非您指定包含或投影。

仅供参考:投影和 Include() 不能一起工作,请参阅此答案如果您进行投影,它将绕过包含。 /sf/answers/501775781/