如何在不包含/加载整个集合的情况下获取实体框架模型中列表的计数?

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

我在 Entity Framework Core 中有一个模型,如下所示:

public class Anime
{
     public int EpisodeCount { get { return Episodes.Count() } }
     public virtual ICollection<Episode> Episodes { get; set; }
}

我遇到的问题是 EpisodeCount 为

0
。目前的解决方案是在我的 EF 查询中运行
.Include(x => x.Episodes)
,但这会在不需要的地方加载整个剧集集合。这也增加了我的 HTTP 请求时间,从 100 毫秒增加到 700 毫秒,这不太好。

我不愿意为了简单的细节而牺牲时间,那么有没有一种解决方案可以让 EF 只查询剧集的 COUNT,而不加载整个集合?

有人建议我这样做

var animeList = context.Anime.ToPagedList(1, 20);
animeList.ForEach(x => x.EpisodeCount = x.Episodes.Count());
return Json(animeList);

但这也会在 EpisodeCount 中返回

0
,所以这不是一个可行的解决方案。

c# entity-framework asp.net-core entity-framework-core
2个回答
14
投票

您需要将所需的数据投影到一个特殊的类(也称为 ViewModel、DTO 等)中。不幸的是(或不是?),为了避免 N + 1 次查询,投影不仅必须包含计数,还必须包含所有其他字段。

例如:

型号:

public class Anime
{
    public int Id { get; set; }
    public string Name { get; set; }
    // other properties...
    public virtual ICollection<Episode> Episodes { get; set; }
}

ViewModel / DTO:

public class AnimeInfo
{
    public int Id { get; set; }
    public string Name { get; set; }
    // other properties...
    public int EpisodeCount { get; set; }
}

然后是以下代码:

var animeList = db.Anime.Select(a => new AnimeInfo
{
    Id = a.Id,
    Name = a.Name,
    EpisodeCount = a.Episodes.Count()
})
.ToList();

生成以下单个 SQL 查询:

SELECT [a].[Id], [a].[Name], (
     SELECT COUNT(*)
     FROM [Episode] AS [e]
     WHERE [a].[Id] = [e].[AnimeId]
) AS [EpisodeCount]
FROM [Anime] AS [a]

0
投票

感谢@ivan-stoev,这是一个很好的答案。但如果你想使用AutoMapper,你可以这样做:

型号:

public class Anime
{
    public string Id { get; set; }
    //...

    public ICollection<Episode> Episodes { get; set; }
    [NotMapped] public int EpisodesCount { get; set; }
}

视图模型/DTO:

public class AnimeDTO
{
    public string Id { get; set; }
    //...

    public int EpisodesCount { get; set; }
}

控制器/存储库:

public async Task<IEnumerable<AnimeDTO>> Get()
{
    var model = await DB.Animes.Select(x => new { Model = x, x.Episodes.Count }).ToListAsync();
    model.ForEach(x => { x.Model.EpisodesCount = x.Count; });
    return mapper.Map<List<AnimeDTO>>(model.Select(x => x.Model));
}
© www.soinside.com 2019 - 2024. All rights reserved.