使用延迟加载时如何避免N + 1

时间:2016-06-30 10:40:25

标签: asp.net entity-framework

我从未使用延迟加载(使用虚拟关键字),因为一旦我尝试,我发现如果我使用延迟加载会出现N + 1问题。

例如,

 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; }  
}

db.Blog.Select(x=> new {
    name = x.Name,
    postCnt = x.Posts.Count()
}).ToList(); 

这不会加入表格,查询将按照帖子数量运行。

所以我这样做,删除'virtual'关键字以进行急切加载。并做

db.Blog.include("Posts").Select(x=> new {
    name = x.Name,
    postCnt = x.Posts.Count()
}).ToList();

我的所有控制器都返回一个Json数据,所以我从不使用延迟加载。

但是,当我看到许多教程或博客时,似乎每个人都在使用虚拟关键字?这让我觉得我错过了什么,我觉得我做错了。

你能告诉我我不理解什么,我做错了什么吗?

  

在急切加载时,我们会尽快将所有对象加载到内存中   对象已创建。

我在一些教程中看到,但我认为,除非使用“include”,否则该对象不会加载任何相关数据。

我是对的吗?或者它还加载所有相关的对象?

[编辑,添加更多示例代码]

public class Post {
    public int Id { get; set; }
    public int BlogId {get; set;}
    public string title { get; set; }

    [ForeignKey("BlogId")]         
    public virtual Blog blog { get; set; }
}


db.Post.Select(x => new {
    id = x.id,
    blogName = x.Blog.name
}).ToLost();

1 个答案:

答案 0 :(得分:0)

在你的案例中有一点我不明白

考虑:

from fd in Folders
select new {
    id = fd.IdFolder,
    c = fd.Files.Count()
}

使用:

Folder {
    /*...*/
    public virtual ICollection<File> Files { get; set; }
}

我得到以下SQL:

SELECT 
    [Extent1].[idDossier] AS [idDossier], 
    (SELECT 
        COUNT(1) AS [A1]
        FROM [dbo].[tableF] AS [Extent2]
        WHERE [Extent1].[idDossier] = [Extent2].[idDossier]) AS [C1]
    FROM [dbo].[tableD] AS [Extent1]

with(或实际上没有虚拟):

Folder {
    /*...*/
    public ICollection<File> Files { get; set; }
}

即使使用了以下内容,我也得到了完全相同的查询:

Folders.Include("Files").
Select( fd => new {
    id = fd.IdFolder,
    c = fd.Files.Count()
})

如果你想要一个连接来获得像:

这样的sql
select
    fd.IdDossier,
    count(fl.idDossier)
from
    tableD fd
    left join tablef fl on fd.IdDossier = fl.idDossier
group by fd.idDossier 

我只是不知道该怎么做

from fd in Folders
join fl in Files on fd.IdFolder equals fl.IdFolder into g
select new {
    id = fd.IdFolder,
    c = g.Count()
}

导致相同的N + 1 SQL