使用 AsNoTracking 过滤 Include 时出现奇怪的行为

Rai*_*iiy 5 c# entity-framework-core .net-core

我不知道是否应该如此,但我认为这很奇怪,因为更改了查询结果。

当我执行下面的查询时,我得到的实体只有 2 个“Mensagens”实体,因为我只过滤活动实体,所以这是正确的,我的数据库上有 2 个活动实体和 1 个非活动实体。

return await context.Lancamentos
            .Include(x => x.UsuarioCriacao)
            .Include(x => x.Mensagens.Where(m => m.Ativo))
            .ThenInclude(m => m.MensagemMedias)
            .ThenInclude(m => m.MediaWhatsapp)
            .ThenInclude(m => m.TipoMediaWhatsapp)
            .Include(x => x.Mensagens.Where(m => m.Ativo))
            .ThenInclude(x => x.TemplateMensagem)
            .ThenInclude(t => t.Medias)
            .ThenInclude(m => m.MediaWhatsapp)
            .ThenInclude(m => m.TipoMediaWhatsapp)
            .AsNoTracking()
            .FirstOrDefaultAsync(l => l.Id == id && l.Ativo);
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

但是,如果我执行完全相同的命令,只是删除该AsNoTracking()行,它就会给我 3 条记录,包括活动的和非活动的。

在此输入图像描述

但非活动的 EF 不会获取ThenInclude以下内容。它改变了行为。

它根据AsNoTracking我使用的过滤器过滤数据Include

如果没有AsNoTracking它,它会给我带来所有数据,但它会过滤是否会加载对象ThenInclude。

有谁知道这是否是正常行为以及为什么会这样?

Iva*_*oev 4

这在Filtered include文档中有所解释:

警告

在跟踪查询的情况下,由于导航修复,过滤包含的结果可能会出乎意料。之前查询过并存储在更改跟踪器中的所有相关实体都将出现在“筛选包含”查询的结果中,即使它们不满足筛选器的要求。在这些情况下使用 Filtered Include 时,请考虑使用NoTracking查询或重新创建 DbContext。

因此,在进行跟踪测试时,您的上下文很可能不干净。即使它是干净的,如果它用于执行其他查询,导航修复程序也可以稍后加载一些不令人满意的过滤器实体,因为它会跟踪(有权访问)所有跟踪的实体。

一般来说,您不能依赖被跟踪实体的导航属性的内容,因为它可能在上下文的生命周期内随时更新,直到上下文被释放或实体与更改跟踪器分离。如果您需要完全控制,则可以不使用跟踪实体查询或 DTO/ViewModel 等投影查询,并准确选择您想要的内容(没有Include/ ThenInclude,只是简单的 LINQ)。