如何在单个查询中获取具有角色的用户?



我已经设置了我的身份模型,如下所述: https://learn.microsoft.com/en-us/aspnet/core/security/authentication/customize-identity-model?view=aspnetcore-2.2#add-user-and-role-navigation-properties

所以我的每个 User 类都有一个角色集合,通过 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();

最新更新