Kas*_*hov 3 c# entity-framework-core asp.net-core asp.net-core-identity
我已经设置了我的身份模型,就像这里描述的那样: https: //learn.microsoft.com/en-us/aspnet/core/security/authentication/customize-identity-model ?view=aspnetcore-2.2#add-user-and -角色导航属性
所以我的每个User类都有一个Roles的集合,通过UserRole“包装器”。所有实体关系都已设置。
当我查询我的用户时,我得到每个用户的所有角色(此处使用延迟加载,但“包含”没有区别):
var users = _userManager.Users
.AsNoTracking()
.ToList();
Run Code Online (Sandbox Code Playgroud)
但是,当检查 EF Core 创建的日志时,我发现每个用户都有另一个查询来获取角色:
[Parameters=[@_outer_Id='d550f61b-ed3d-4d90-8e7b-31552de50d3b' (Size = 450)], CommandType='"Text"', CommandTimeout='30']
SELECT [r].[RoleId] AS [Id], [r.Role].[Name], [r.Role].[DisplayName]
FROM [AspNetUserRoles] AS [r]
INNER JOIN [AspNetRoles] AS [r.Role] ON [r].[RoleId] = [r.Role].[Id]
WHERE ([r].[Discriminator] = N'UserRole') AND (@_outer_Id = [r].[UserId])
Run Code Online (Sandbox Code Playgroud)
这会针对数据库中的每个用户 ID 重复进行。
如何仅使用一个查询即可获得结果?
以防万一,我的模型:
public class User : IdentityUser
{
public virtual ICollection<UserRole> UserRoles { get; set; }
}
public class UserRole : IdentityUserRole<string>
{
public virtual User User { get; set; }
public virtual Role Role { get; set; }
}
public class Role : IdentityRole
{
public virtual ICollection<UserRole> UserRoles { get; set; }
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<User>(b =>
{
b.HasMany(e => e.UserRoles)
.WithOne(e => e.User)
.HasForeignKey(ur => ur.UserId)
.IsRequired();
});
modelBuilder.Entity<Role>(b =>
{
b.HasMany(e => e.UserRoles)
.WithOne(e => e.Role)
.HasForeignKey(ur => ur.RoleId)
.IsRequired();
});
}
Run Code Online (Sandbox Code Playgroud)
看来您启用了延迟加载。EF 永远不会自动连接相关表,您必须以某种方式指示它这样做。在延迟加载的情况下,这是通过访问导航属性的 getter 来实现的。getter 被 EF 重写,以从对象缓存中提取相关实体,如果在那里找不到它们,则发出查询来检索它们(因此称为“惰性”)。显然,您只是迭代用户并访问UserRoles每个用户的成员,这会导致为每个用户发出单独的查询。
相反,您想要做的是立即加载关系。Include您可以通过(以及ThenInclude子关系)来执行此操作。换句话说:
var users = await _userManager.Users
.Include(x => x.UserRoles)
.ThenInclude(x => x.Role)
.AsNoTracking()
.ToListAsync();
Run Code Online (Sandbox Code Playgroud)