我已经像这里描述的那样设置了我的身份模型: https://learn.microsoft.com/en-us/aspnet/core/security/authentication/customize-identity-model?view=aspnetcore-2.2#add-user-and-role-navigation-properties
所以我的每个用户类都有一个角色集合,通过 UserRole“包装器”。 所有的实体关系都设置好了。
当我查询我的用户时,我得到了每个用户的所有角色(在这里使用延迟加载,但“包含”没有区别):
var users = _userManager.Users
.AsNoTracking()
.ToList();
但是在检查 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])
这对我数据库中的每个用户 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();
});
}
最佳答案
看起来您启用了延迟加载。 EF 永远不会自动连接相关表,您必须以某种方式指示它这样做。在延迟加载的情况下,这是通过访问导航属性的 getter 来实现的。 EF 覆盖 getter 以从对象缓存中提取相关实体,如果在那里找不到它们,则发出查询以检索它们(因此是“惰性”)。您显然只是在遍历用户并为每个用户访问 UserRoles
成员,这会导致为每个用户发出单独的查询。
您要做的是急切加载关系。您可以通过 Include
(对于子关系使用 ThenInclude
)执行此操作。换句话说:
var users = await _userManager.Users
.Include(x => x.UserRoles)
.ThenInclude(x => x.Role)
.AsNoTracking()
.ToListAsync();
关于c# - 如何在一个查询中获取具有角色的用户?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57910856/