我目前正在使用这种方法通过以下方式加载实体及其相关实体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上的代码详细信息:链接
可以,但是在迁移到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上的代码详细信息:链接
不幸的是,我尝试使用该AsNoTracking
方法重写此示例,但是它不起作用-未加载相关实体。
如何使用AsNoTracking方法通过更快的性能重写原始查询?
我不需要针对我的用例跟踪客户端实体。
正如EF Core文档所说,v3现在会生成联接,并且该查询是笛卡尔爆炸问题 的受害者https://docs.microsoft.com/zh-cn/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;
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句