如何在使用惰性加载时避免N+1



我从来没有使用过延迟加载(使用virtual关键字),因为,一旦我尝试过,我发现如果我使用延迟加载有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();

你的情况我有一点不明白

考虑:

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]

带(或实际上不带):

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

我得到了完全相同的查询,即使:

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

如果你想要一个join来获取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

最新更新