#c# #linq #asp.net-identity
#c# #linq #asp.net-идентификатор
Вопрос:
У меня есть этот LINQ:
var users = _ctx.Users
.AsEnumerable() // or "InvalidOperationException: This may indicate either a bug or a limitation in EF Core"
.GroupJoin(_ctx.UserClaims, u => u.Id, c => c.UserId, (user, claims) => new { user, claims })
.GroupJoin(_ctx.UserRoles, uc => uc.user.Id, r => r.UserId, (uc, roles) => new { uc.user, uc.claims, roles })
.ToList()
.Select(ucr => new UserDto
{
Id = ucr.user.Id,
UserName = ucr.user.UserName,
FirstName = ucr.user.FirstName,
LastName = ucr.user.LastName,
LastLogin = ucr.user.LastLogin,
LockoutEnd = ucr.user.LockoutEnd,
LockoutEnabled = ucr.user.LockoutEnabled,
Roles = ucr.roles.Select(x => x.RoleId).Distinct().ToList(), // Here i would like the Role Name from the Roles Table by the UserRoles
Scopes = ucr.claims.Select(x => x.ToClaim()).Where(x => x.Type.Equals(Shared.Scopes.Key)).Select(x => x.Value).ToList(),
Claims = ucr.claims.Select(x => x.ToClaim()).Where(x => !x.Type.Equals(Shared.Scopes.Key)).ToList(),
Enabled = ucr.user.Enabled
}
).ToList();
Это работает отлично, но я хотел бы получить фактические роли для пользователя, а не только сопоставление роли пользователя с ролью из пользовательских ролей
Я попытался добавить дополнительное групповое соединение: .GroupJoin(_ctx.Roles, ucr => ucr.roles.Id, r => r.Id, (ucr, r) => new { u, r })
но поскольку roles
это список, я получаю сообщение об ошибке:
‘IEnumerable<IdentityUserRole>’ не содержит определения для ‘Id’ и не имеет доступного метода расширения ‘Id’, принимающего первый аргумент типа ‘IEnumerable<IdentityUserRole>’
Есть идеи, как я могу также получить фактический список ролей?
Я использую классы идентификаторов по умолчанию, отличные от ApplicationUser
public class ApplicationUser : IdentityUser
{
/// <summary>
/// First Name
/// </summary>
[Display(Name = "First Name")]
public string FirstName { get; set; }
/// <summary>
/// Last Name
/// </summary>
[Display(Name = "Last Name")]
public string LastName { get; set; }
/// <summary>
/// Profile Picture
/// </summary>
public byte[] ProfilePicture { get; set; }
/// <summary>
/// Enabled
/// </summary>
public bool Enabled { get; set; }
/// <summary>
/// Last Login
/// </summary>
[Display(Name = "Last Login")]
[DataType(DataType.DateTime)]
[DisplayFormat(ApplyFormatInEditMode = true, NullDisplayText = "N/A", DataFormatString = "{0:yyyy-MM-dd HH:mm}")]
public DateTime? LastLogin { get; set; } = null;
/// <summary>
/// Display Name
/// </summary>
[NotMapped]
public string DisplayName => $"{FirstName} {LastName}";
}
и UserDTO
public class UserDto
{
public UserDto()
{
Id = Guid.NewGuid().ToString();
ConcurrencyStamp = Guid.NewGuid().ToString();
}
public string Id { get; set; }
public string UserName { get; set; }
public string NormalizedUserName => UserName.ToUpper();
public string Email => UserName;
public string NormalizedEmail => Email.ToUpper();
public bool EmailConfirmed { get; set; }
public string PasswordHash { get; set; }
public string SecurityStamp { get; set; }
public string ConcurrencyStamp { get; set; }
public string PhoneNumber { get; set; }
public bool PhoneNumberConfirmed { get; set; }
public bool TwoFactorEnabled { get; set; }
public DateTimeOffset? LockoutEnd { get; set; }
public bool LockoutEnabled { get; set; }
public int AccessFailedCount { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public byte[] ProfilePicture { get; set; }
public DateTime? LastLogin { get; set; }
public bool Enabled { get; set; }
public List<string> Roles { get; set; }
public List<Claim> Claims { get; set; }
public List<string> Scopes { get; set; }
}
Комментарии:
1. Есть ли шанс, что вы могли бы показать запрос, который не выполняется? А также предоставить полное определение класса для всех задействованных классов?
2. @Enigmativity, я использую классы идентификаторов по умолчанию, которые я добавил
ApplicationUser
, и дополнительныеGroupJoin
, которые я пытался добавить.
Ответ №1:
Объединение UserRoles
и Roles
, поэтому используйте групповое объединение.
var users = _ctx.Users
.AsEnumerable()
.GroupJoin(_ctx.UserClaims, u => u.Id, c => c.UserId, (user, claims) => new { user, claims })
.GroupJoin(
_ctx.UserRoles.Join(_ctx.Roles, ur => ur.RoleId, r => r.Id, (userRole, role) => new { userRole, role }),
uc => uc.user.Id, r => r.userRole.UserId,
(uc, roles) => new { uc.user, uc.claims, roles})
.Select(ucr => new
{
Id = ucr.user.Id,
UserName = ucr.user.UserName,
FirstName = ucr.user.FirstName,
LastName = ucr.user.LastName,
LastLogin = ucr.user.LastLogin,
LockoutEnd = ucr.user.LockoutEnd,
LockoutEnabled = ucr.user.LockoutEnabled,
Roles = ucr.roles.Select(x => x.role.Name).Distinct().ToList(),
Scopes = ucr.claims.Select(x => x.ToClaim()).Where(x => x.Type.Equals(Shared.Scopes.Key)).Select(x => x.Value).ToList(),
Claims = ucr.claims.Select(x => x.ToClaim()).Where(x => !x.Type.Equals(Shared.Scopes.Key)).ToList(),
Enabled = ucr.user.Enabled
}
).ToList();
Комментарии:
1. Спасибо, я даже не думал, что это возможно! Большое вам спасибо, работает так, как ожидалось.