EF Core 警告 - 调用 Include() 和 ThenInclude()

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

我有以下实体(多对多关系):

public class Fragrance
{
    public int FragranceId { get; set; }
    public string Brand { get; set; } = null!;
    public string Name { get; set; } = null!;
    public string Gender { get; set; } = null!;
    public int LaunchYear { get; set; }
    public virtual List<Note>? Notes { get; set; }
}

public class Note
{
    public int NoteId { get; set; }
    public string Name { get; set; } = null!;
    public string Description { get; set; } = null!;
    public virtual List<Fragrance>? Fragrances { get; set; }
}

public class FragranceNote
{
    public int FragranceId { get; set; }
    public Fragrance Fragrance { get; set; } = null!;
    public int NoteId { get; set; }
    public Note Note { get; set; } = null!;
}

当用户发送包含香水 ID 的 http 请求时,我想要一个包含来自给定香水的 2 个随机音符的响应,每个音符包含 2 个其他随机香水(与用户发送的不同)。

[
    {
        "name": "Bergamot",
        "fragrances": [
            {
                "fullName": "Maison Francis Kurkdjian  Oud Silk Mood",
                "gender": "Unisex"
            },
            {
                "fullName": "Dolce & Gabbana Light Blue Forever",
                "gender": "Male"
            }
        ]
    },
    {
        "name": "Pink Pepper",
        "fragrances": [
            {
                "fullName": "Maison Margiela Replica Jazz Club",
                "gender": "Male"
            },
            {
                "fullName": "Dior Ambre Nuit",
                "gender": "Unisex"
            }
        ]
    }
]

我的 EF 查询 看起来像这样:

var notes = _context.Fragrances
    .Where(f => f.FragranceId == fragranceId)
    .Include(
        f => f.Notes!
        .OrderBy(r => Guid.NewGuid())
        .Take(2)
    )
    .ThenInclude(
        n => n.Fragrances!
        .Where(f => f.FragranceId != fragranceId)
        .OrderBy(r => Guid.NewGuid())
        .Take(2)
    )
    .First().Notes;

它有效,但我有这个警告:

编译一个查询,通过“包含”或通过投影加载多个集合导航的相关集合,但尚未配置“QuerySplittingBehavior”。默认情况下,实体框架将使用“QuerySplittingBehavior.SingleQuery”,这可能会导致查询性能降低。

我尝试使用

AsSplitQuery()
,但它弄乱了我的响应并且无法加载正确的数据。

c# entity-framework linq entity-framework-core
1个回答
0
投票

罪魁祸首将是

OrderBy
/
Include
中的
ThenInclude
这不适用于拆分查询,因为拆分将尝试加载相关注释的所有香水,然后随机订购完整的集合并取顶部2. 因此,它为每个香调挑选的最终香水是从所有选定香调的香水中提取的,从而导致不匹配。

警告是,您正在生成一个潜在的大型笛卡尔积,EF 警告该积可能会影响性能。拆分查询可以避免这种情况,但有局限性,特别是在排序方面,因为它试图拆分相关查询,而不会像延迟加载那样严重。

看起来您正在为某种特定的香水挑选两种随机香调,然后随机挑选两种与该香调相关的香水? (不排除您最初选择的香水)您应该能够做到这一点并避免警告:

var notes = _context.Notes
    .Where(n => n.Fragrances.Any(f => f.FragranceId == fragranceId)
    .Include(n => n.Fragrances
        .OrderBy(f => Guid.NewGuid())
        .Take(2))
    .OrderBy(n => Guid.NewGuid())
    .Take(2);

我相信在没有笛卡尔警告的情况下应该会给你相同的预期结果。如果您想排除所选的香水 ID,则:

    .Include(n => n.Fragrances
        ,Where(f -> f.FragranceId != fragranceId)
        .OrderBy(f => Guid.NewGuid())
        .Take(2))
© www.soinside.com 2019 - 2024. All rights reserved.