asp.net-core - 如何使用 'AsNoTracking' 方法结合显式加载相关实体在 EF Core 中加载实体

标签 asp.net-core .net-core ef-core-3.0

我目前正在使用这种方法来加载实体及其相关实体 AsNoTracking :

await DbContext.Clients
                .Include(x => x.AllowedGrantTypes)
                .Include(x => x.RedirectUris)
                .Include(x => x.PostLogoutRedirectUris)
                .Include(x => x.AllowedScopes)
                .Include(x => x.ClientSecrets)
                .Include(x => x.Claims)
                .Include(x => x.IdentityProviderRestrictions)
                .Include(x => x.AllowedCorsOrigins)
                .Include(x => x.Properties)
                .Where(x => x.Id == clientId)
                .AsNoTracking()
                .SingleOrDefaultAsync();

Github上的代码详细信息:link

这有效,但在迁移到 EF Core 3.0 后,此查询非常慢。

我发现可以通过像这样明确加载相关实体来解决这个性能问题:

IQueryable<Entities.Client> baseQuery = Context.Clients
                .Where(x => x.Id == clientId)
                .Take(1);

            var client = await baseQuery.FirstOrDefaultAsync();
            if (client == null) return null;

            await baseQuery.Include(x => x.AllowedCorsOrigins).SelectMany(c => c.AllowedCorsOrigins).LoadAsync();
            await baseQuery.Include(x => x.AllowedGrantTypes).SelectMany(c => c.AllowedGrantTypes).LoadAsync();
            await baseQuery.Include(x => x.AllowedScopes).SelectMany(c => c.AllowedScopes).LoadAsync();
            await baseQuery.Include(x => x.Claims).SelectMany(c => c.Claims).LoadAsync();
            await baseQuery.Include(x => x.ClientSecrets).SelectMany(c => c.ClientSecrets).LoadAsync();
            await baseQuery.Include(x => x.IdentityProviderRestrictions).SelectMany(c => c.IdentityProviderRestrictions).LoadAsync();
            await baseQuery.Include(x => x.PostLogoutRedirectUris).SelectMany(c => c.PostLogoutRedirectUris).LoadAsync();
            await baseQuery.Include(x => x.Properties).SelectMany(c => c.Properties).LoadAsync();
            await baseQuery.Include(x => x.RedirectUris).SelectMany(c => c.RedirectUris).LoadAsync();


Github上的代码详细信息:link

不幸的是,我尝试用 AsNoTracking 重写这个示例。方法,但它不起作用 - 未加载相关实体。

如何使用 AsNoTracking 方法通过更快的性能重写我的原始查询?

我不需要为我的用例跟踪客户端实体。

最佳答案

正如 EF Core 文档所说,v3 现在生成连接,并且此查询是笛卡尔爆炸问题的受害者 https://docs.microsoft.com/en-us/ef/core/querying/related-data

文档还说,在以前的版本中,EF 为每个包含生成单独的查询。所以在我看来很好的解决方案是

var baseEntity = await DbContext.Clients.AsNoTracking().SingleOrDefaultAsync(x => x.Id == clientId);
baseEntity.AllowedGrantTypes = await DbContext.ClientCorsOrigins.AsNoTracking().Where(x => x.ClientId == clientID).ToListAsync();
baseEntity.RedirectUris = await DbContext.ClientRedirectUris.AsNoTracking().Where(x => x.ClientId == clientID).ToListAsync();
...
...

依此类推,直到您获得所需的所有相关资源。它将模仿以前的行为。
如果您确实需要使用导航属性,则不能使用 .AsNoTracking()很遗憾。如果我的想法看起来太天真 - 我能想到的唯一其他方法是在使用导航属性后将实体与跟踪上下文分离。

因此,从第二个链接实现代码后,您需要遍历对象中的实体并将它们标记为分离DbContext.Entry(entity).State = EntityState.Detached;

关于asp.net-core - 如何使用 'AsNoTracking' 方法结合显式加载相关实体在 EF Core 中加载实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61316867/

相关文章:

c# - SignalR Core 2.2 CORS AllowAnyOrigin() 重大变更

asp.net - IIS Express 自签名证书不受信任

entity-framework - 在 EF Core 2.0 中使用 OwnsOne 方法映射属性

c# - Entity Framework Core 3 原始 SQL 缺少方法

c# - 使用 EF Core 加载和保存内存中 SQLite 数据库

asp.net-core - 尝试运行项目模型服务器进程 (1.0.0-rc4-004771) 时发生以下错误

c# - _Layout.cshtml 的本地化

javascript - 如何显示select2中的输入框?

.net - .NET Core 的地理空间库?

c# - EF Core 无法确定抽象类中外键表示的关系